changed names, some may not be right.
authorChris Koeritz <fred@gruntose.com>
Mon, 30 Apr 2012 16:24:20 +0000 (12:24 -0400)
committerChris Koeritz <fred@gruntose.com>
Mon, 30 Apr 2012 16:24:20 +0000 (12:24 -0400)
183 files changed:
huffware/documentation/jaunting_readme.txt [new file with mode: 0644]
huffware/huffotronic_jaunter_updater_v5.1/Hyper_Jump_Wilder_Westen_v0.2.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/Hyper_Jump_Wilder_Westen_v0.2.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/a_huffotronic_update_server_v23.2.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/a_huffotronic_update_server_v23.2.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/child_jaunter_v85.2.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/child_jaunter_v85.2.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/coastal_connector_hubs_v2.4.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/coastal_connector_hubs_v2.4.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/data_cow_v3.3.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/data_cow_v3.3.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/fred_main_hubs_v5.4.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/fred_main_hubs_v5.4.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/huff-update_client_v20.1.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/huff-update_client_v20.1.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/jaunt_config_funcs_v2.9.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/jaunt_config_funcs_v2.9.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/jaunt_rezolator_v22.3.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/jaunt_rezolator_v22.3.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/jaunt_wik_rez_v86.3.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/jaunt_wik_rez_v86.3.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/jaunter_button_pusher_v0.8.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/jaunter_button_pusher_v0.8.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/jaunting_library_v15.9.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/jaunting_library_v15.9.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/menutini_library_v5.9.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/menutini_library_v5.9.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/noteworthy_library_v12.4.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/noteworthy_library_v12.4.txt [deleted file]
huffware/huffotronic_jaunter_updater_v5.1/texture_mover_v3.0.lsl [new file with mode: 0755]
huffware/huffotronic_jaunter_updater_v5.1/texture_mover_v3.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/Hour_Hand_v0.5.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/Hour_Hand_v0.5.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/Minute_Hand_v0.4.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/Minute_Hand_v0.4.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/NC_stay_at_home_v5.2.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/NC_stay_at_home_v5.2.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/Vote_for_me_v4.2.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/Vote_for_me_v4.2.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/a_huffotronic_update_server_v23.2.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/a_huffotronic_update_server_v23.2.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/a_jumping_bean_v2.7.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/a_jumping_bean_v2.7.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/altitudinator_v1.1.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/altitudinator_v1.1.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/ama_omega_et_al_vendor_owner-only_v0.5.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/ama_omega_et_al_vendor_owner-only_v0.5.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/animated_texture_v0.4.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/animated_texture_v0.4.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/axis_rider_v2.9.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/axis_rider_v2.9.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/base_note_read_v0.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/base_note_read_v0.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/begging_bowl_v4.4.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/begging_bowl_v4.4.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/bouncer_v2.0.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/bouncer_v2.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/box_mover_v1.7.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/box_mover_v1.7.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/button_pusher_v0.5.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/button_pusher_v0.5.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/chaos_picks_a_number_v3.0.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/chaos_picks_a_number_v3.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/collider_v1.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/collider_v1.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/comfortable_sitting_v7.5.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/comfortable_sitting_v7.5.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/die_on_demand_v0.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/die_on_demand_v0.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/email_notecards_v6.0.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/email_notecards_v6.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/hamster_sound_effects_v0.8.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/hamster_sound_effects_v0.8.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/html_onna_prim_v1.6.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/html_onna_prim_v1.6.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/huff-update_client_v20.1.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/huff-update_client_v20.1.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/invisiprim_v0.8.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/invisiprim_v0.8.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/link_reporter_v0.5.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/link_reporter_v0.5.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/logic_system_main_v1.8.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/logic_system_main_v1.8.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/megaprim_v0.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/megaprim_v0.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/mu_tester_v6.0.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/mu_tester_v6.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/no_sitting_on_vendor_v1.0.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/no_sitting_on_vendor_v1.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/noteworthy_example_usage_v3.6.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/noteworthy_example_usage_v3.6.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/report_to_merchants_v1.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/report_to_merchants_v1.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/set_roundy_v0.6.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/set_roundy_v0.6.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/simple_map_tp_v0.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/simple_map_tp_v0.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/simpy_pet_v3.7.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/simpy_pet_v3.7.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/sit_testing_v0.6.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/sit_testing_v0.6.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/swiveller_v1.1.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/swiveller_v1.1.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/tester_for_inventory_exchanger_v1.0.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/tester_for_inventory_exchanger_v1.0.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/time_zone_picker_v0.6.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/time_zone_picker_v0.6.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/timed_expiration_v2.9_(toxic)_.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/timed_expiration_v2.9_(toxic)_.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/touchy_feely_doro_v0.4.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/touchy_feely_doro_v0.4.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/turbo_lifter_v5.7.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/turbo_lifter_v5.7.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/uuid_shower_mat_v0.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/uuid_shower_mat_v0.3.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/vendor_sales_manager_v3.1.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/vendor_sales_manager_v3.1.txt [deleted file]
huffware/huffotronic_tools_n_testers_v6.1/zap_updater_from_elevators_v1.3.lsl [new file with mode: 0755]
huffware/huffotronic_tools_n_testers_v6.1/zap_updater_from_elevators_v1.3.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/FPS_color_changer_v2.4.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/FPS_color_changer_v2.4.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/FreeView_v1.8.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/FreeView_v1.8.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/JukeBox_v1.6.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/JukeBox_v1.6.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/TL_Door_fredmod_v4.4.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/TL_Door_fredmod_v4.4.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/a_huffotronic_update_server_v23.2.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/a_huffotronic_update_server_v23.2.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/auto-retire_v2.8.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/auto-retire_v2.8.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/card_configurator_v8.1.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/card_configurator_v8.1.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/clear_text_and_effects_v2.2.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/clear_text_and_effects_v2.2.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/comfortable_sitting_v7.5.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/comfortable_sitting_v7.5.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/create_objects_v1.3.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/create_objects_v1.3.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/data_cow_v3.3.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/data_cow_v3.3.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/fade_opacity_v3.7.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/fade_opacity_v3.7.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/fredboxmux_no_rot_v3.0.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/fredboxmux_no_rot_v3.0.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/fredboxmux_v3.0.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/fredboxmux_v3.0.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/huff-update_client_v20.1.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/huff-update_client_v20.1.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/hufflets_v6.3.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/hufflets_v6.3.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/huffware_id_registry_v3.2.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/huffware_id_registry_v3.2.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/inventory_exchanger_v3.7.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/inventory_exchanger_v3.7.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/license__free_in_osgrid_only_v1.8.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/license__free_in_osgrid_only_v1.8.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/menu_list_manager_v12.4.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/menu_list_manager_v12.4.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/menutini_library_v5.9.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/menutini_library_v5.9.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/non-script_giver_v2.8.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/non-script_giver_v2.8.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/noteworthy_library_v12.4.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/noteworthy_library_v12.4.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/particle_projector_v3.1.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/particle_projector_v3.1.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/party_culiar_v5.7.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/party_culiar_v5.7.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/rotanium_rotato_v2.7.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/rotanium_rotato_v2.7.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/take_touches_v0.2.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/take_touches_v0.2.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/text_label_v3.9.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/text_label_v3.9.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/texture_mover_v3.0.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/texture_mover_v3.0.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/texture_shower_v2.7.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/texture_shower_v2.7.txt [deleted file]
huffware/huffotronic_updater_freebie_v5.3/zenmondos_mailbox_v0.4.lsl [new file with mode: 0755]
huffware/huffotronic_updater_freebie_v5.3/zenmondos_mailbox_v0.4.txt [deleted file]
huffware/jaunting/jaunting_library_v15.9.lsl [deleted file]
huffware/jaunting/readme.txt [deleted file]

diff --git a/huffware/documentation/jaunting_readme.txt b/huffware/documentation/jaunting_readme.txt
new file mode 100644 (file)
index 0000000..f60166d
--- /dev/null
@@ -0,0 +1,10 @@
+
+Jaunting is our term for teleporting around the grid.  The term jaunt comes
+from 'The Stars My Destination' by Alfred Bester and we refer to it in a
+similar context.
+
+The jaunting library script is the useful encapsulation of a variety of
+teleportation and movement control methods.  It is interfaced to via a
+huffware API for remote procedure calls.
+
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/Hyper_Jump_Wilder_Westen_v0.2.lsl b/huffware/huffotronic_jaunter_updater_v5.1/Hyper_Jump_Wilder_Westen_v0.2.lsl
new file mode 100755 (executable)
index 0000000..0c23192
--- /dev/null
@@ -0,0 +1,28 @@
+string hower = "Hyper Jump\n* Wilder Westen *";     // Hover text
+vector color = <0,0,0>;                 // color of the hover text
+string sim = "grid-ww.talentraspel.de:9000:Wilder Westen";     // ip/name + port of the target
+
+vector pos = <147,158,25>;              // position
+
+
+key user;
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        llSetText(hower,color,1);
+    }
+    
+    touch_start(integer total_number) {
+        user = llDetectedKey(0); 
+        llMapDestination (sim, pos, <1,1,1>);
+    }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/Hyper_Jump_Wilder_Westen_v0.2.txt b/huffware/huffotronic_jaunter_updater_v5.1/Hyper_Jump_Wilder_Westen_v0.2.txt
deleted file mode 100755 (executable)
index 0c23192..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-string hower = "Hyper Jump\n* Wilder Westen *";     // Hover text
-vector color = <0,0,0>;                 // color of the hover text
-string sim = "grid-ww.talentraspel.de:9000:Wilder Westen";     // ip/name + port of the target
-
-vector pos = <147,158,25>;              // position
-
-
-key user;
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        llSetText(hower,color,1);
-    }
-    
-    touch_start(integer total_number) {
-        user = llDetectedKey(0); 
-        llMapDestination (sim, pos, <1,1,1>);
-    }
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/a_huffotronic_update_server_v23.2.lsl b/huffware/huffotronic_jaunter_updater_v5.1/a_huffotronic_update_server_v23.2.lsl
new file mode 100755 (executable)
index 0000000..ef201cf
--- /dev/null
@@ -0,0 +1,940 @@
+
+// huffware script: huff-update server, by fred huffhines.
+//
+// this script is the server side of the update process.  it should reside in an object that
+// has all the newest versions of scripts and objects that will be updated.  when rezzed, and
+// at periodic intervals, it announces on a private chat channel that updates are available.
+// when objects respond that they might like an update, it tells them the scripts that it has
+// stored inside of it.  if any of those scripts are an older version inside the client
+// (update requesting) object, then the client will request the newer versions.  the server
+// object will stuff them into it and tell them to start running.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer IS_OPENSIM = TRUE;  // must be set to true for opensim, false for second life.
+
+integer DEBUGGING = FALSE;  // set this to true for noisier diagnostics.
+
+
+
+// updater dependency section:
+// should be moved to a notecard!!!
+//
+// format is a list of strings, where each string has a pair wrapped by the
+// huffware item separators.  the pair contains (1) the basename of a script
+// that has a new dependency and (2) the basename of that new dependency.
+list known_script_dependencies;
+
+
+
+
+load_script_deps()
+{
+    known_script_dependencies = [
+        llDumpList2String(["jaunt wik rez", "jaunt config funcs"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["jaunt wik rez", "data cow"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["jaunt wik rez", "jaunt rezolator"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["remotely personable", "inventory exchanger"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "exchange driver hudimation"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "avatar timer manager"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "avatar choice memory"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["giftorse", "particle projector"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["huff-search brainiac", "searchbert armature"], ITEM_LIST_SEPARATOR),
+
+        
+//special purpose -- removes the updater from the elevator buttons...
+//llDumpList2String(["comfortable sitting", "zap updater from elevators"], ITEM_LIST_SEPARATOR),
+// => do not uncomment unless you want your elevators to shed their ability to update.
+
+
+        // this allows us to add or remove items above at will without complaints about comma.
+        llDumpList2String(["xyzzy", "hopefully-never-matches"], ITEM_LIST_SEPARATOR)
+    ];
+}
+
+
+
+
+// global constants...
+
+integer USER_COMMAND_CHANNEL = 4;  // channel where we listen to user commands.
+
+float ANNOUNCEMENT_PERIOD = 14.0;  // how often we tell other objects that we have tasty treats.
+
+integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
+integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
+
+string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
+string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
+string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
+string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
+string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
+string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
+string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
+string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
+string DONE_UPDATING                = "#finito#";  // the client is done updating.
+string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
+
+integer UPDATER_SCRIPT_PIN          = -1231008;  // the hook for our scripts to be modified.
+
+string RESTART_UPDATER_COMMAND      = "#restart";  // said in open chat to recrank the updater.
+string SHOW_SCRIPTS_COMMAND         = "#show";  // said in open chat to list out the scripts.
+string SHUTDOWN_COMMAND             = "#destroy";  // shuts down object and destroys it.
+
+string UPDATER_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+
+string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
+
+integer ENTRIES_PER_LINE = 4;  // number of items from a list shown on one line of text.
+
+integer MAXIMUM_ACTIVE_CLIENTS = 5;  // number of conversations we will allow at a time.
+
+float LONGEST_SLACK_PER_CLIENT = 84.0;
+    // we allow a client to be out of touch with us for this many seconds.  after that,
+    // we decide it's deceased and remove it from our list.
+
+integer MESSAGE_SIZE_LIMIT = 800;  // longest thing that can be safely said without clipping (guess).
+
+float SCRIPT_LIST_PAUSE_INTERVAL = 1.4;  // pause between large chunks of update text.
+
+string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
+
+float CHANGED_INVENTORY_SNOOZER = 7.0;
+    // the number of seconds we sleep once we see an inventory change.  we don't want to
+    // react to this immediately.  this overrides the normal announcement cycle until it's
+    // dealt with by the timer.
+
+string CONTINUANCE_MARKER = "...";
+    // a string sent when the update list is too long and needs to be continued in another chat.
+
+string UPDATER_BASE_NAME = "huff-update client";
+    // the name of the updater script that keeps everything in sync.
+
+//////////////
+
+// global variables...
+
+list scripts_available;  // the list of scripts we have in our inventory for distribution.
+list objects_available;  // list of objects for handing out.
+
+list active_clients;  // list of keys for clients that are updating currently.
+list active_update_channels;  // active conversations on client chosen channels.
+list active_listen_ids;  // the ids for the listener on those channels.
+list active_timestamps;  // tracks when the client was last active.
+
+integer inventory_request_channel;  // our personal channel that the update client should talk with.
+
+integer dealing_with_change;  // has the inventory changed?  we will deal with this in the timer.
+
+// displays the status of the update server.
+show_status(key who_says)
+{
+    string title = "[mem free=" + (string)llGetFreeMemory() + "]";
+    title = "Listening for requests on channel " + (string)inventory_request_channel;
+    if (llGetListLength(active_update_channels))
+        title += "\nactive channels="
+            + dump_list(active_update_channels, FALSE, ENTRIES_PER_LINE);
+    else
+        title += "\nNo channels active.";
+        
+    if (llGetListLength(active_clients))
+        title += "\nactive clients=" + dump_keyed_list(active_clients, TRUE, 2);
+    else
+        title += "\nNo clients active.";
+    
+    if (llGetOwner() == who_says) {
+        string addition = " ";
+        if (USER_COMMAND_CHANNEL != 0) addition = "/" + (string)USER_COMMAND_CHANNEL + " ";
+        title += "\n[ \"" + addition + SHOW_SCRIPTS_COMMAND + "\" lists all the scripts, "
+            + "\"" + addition + SHUTDOWN_COMMAND + "\" zaps the updater, "
+            + "\"" + addition + RESTART_UPDATER_COMMAND + "\" refreshes the updater ]";
+    }
+
+    llWhisper(0, title);
+}
+
+// plink a quietous string of resonance...
+squonk(integer indy)
+{
+    string snd = llGetInventoryName(INVENTORY_SOUND, indy);
+    if (snd != "") llTriggerSound(snd, 1.0);
+}
+
+// list out the scripts that the server's object contains.
+show_scripts()
+{
+    string title = (string)llGetListLength(scripts_available) + " scripts available:";
+    show_list(title, scripts_available);
+    title = (string)llGetListLength(objects_available) + " objects available:";
+    show_list(title, objects_available);
+}
+
+// lets the client know that we're here and have some scripts available.
+announce_presence()
+{
+    if (llGetListLength(active_clients) < MAXIMUM_ACTIVE_CLIENTS) {
+        // only announce if we're not already booked up.
+        llWhisper(UPDATE_ANNOUNCEMENT_CHANNEL, UPDATE_ANNOUNCEMENT_PREFIX + (string)inventory_request_channel);
+    }
+}
+
+// lifted from "clear text and effects" script; should be nearly identical
+// to that, except that we set the texture animation.
+reset_all_effects()
+{
+    llSetText("", <0,0,0>, 0);  // clear any text above object.
+    llSetSitText("Sit Here");  // reset sit text to default state.
+    llSetTouchText("Touch");  // similarly for touch.
+    llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
+    llParticleSystem([]);  // turn off all particles.
+    llSensorRemove();  // stop any running sensors.
+    llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
+    llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
+    // keep it from being physical and from disapparating.
+    llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE,
+        PRIM_PHANTOM, TRUE]);
+    llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
+
+    //
+    // the following are specific to the huffotronic update server.
+    //
+
+    // we re-assert our special texture set here, in case some wayward scripts have
+    // messed with us.
+    integer textures_held = llGetInventoryNumber(INVENTORY_TEXTURE);
+    integer indy;
+    for (indy = 0; indy < textures_held; indy++) {
+        string curr_tex = llGetInventoryName(INVENTORY_TEXTURE, indy);
+        // we have a simple scheme for putting textures on the updater.
+        // we have an inside, an outside and the ends.
+        if (is_prefix(curr_tex, "~~s0")) {
+            llSetTexture(curr_tex, ALL_SIDES);
+        } else if (is_prefix(curr_tex, "~~s1")) {
+            llSetTexture(curr_tex, 1);
+        } else if (is_prefix(curr_tex, "~~s2")) {
+            llSetTexture(curr_tex, 0);
+            llSetTexture(curr_tex, 3);
+        }
+    }
+    
+    // re-assert our texture animation also.
+    llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE,
+        ALL_SIDES, 0, 0, 0, TWO_PI, 1.0 / 36.0);
+}
+
+// set up the update server object.
+initialize_root()
+{
+    // set up our particular "look".
+    reset_all_effects();
+
+    // shut down any competing scripts in this object.
+    // we try to swat any other script that's been added before we let them do weird
+    // stuff.  for example, a pet script might start acting like one.  this
+    // function is not guaranteed to run before that bad stuff can happen,
+    // and that's maybe the one major issue with this approach.  as long as
+    // the contained scripts aren't evil (like if they jump someplace else
+    // as soon as they start), then there shouldn't be any serious problems.
+    knock_down_other_scripts();
+
+    // reset our variables.
+    active_update_channels = [];
+    active_listen_ids = [];
+    active_clients = [];
+    active_timestamps = [];
+    scripts_available = [];
+    objects_available = [];
+    dealing_with_change = FALSE;  // not handling any inventory changes.
+
+    // make sure we know about any scripts that have new dependencies.
+    load_script_deps();
+
+    // clean out any older versions of the scripts before we make our
+    // inventory.
+    destroy_older_versions();
+
+    // now accumulate the list of scripts in our inventory.    
+    integer items_held = llGetInventoryNumber(INVENTORY_SCRIPT);
+    integer indy;
+    for (indy = 0; indy < items_held; indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        // we don't provide our own script for updating; it must be kept from
+        // floating around, like into other objects that are not updaters.
+////        if (curr_script != llGetScriptName())
+            scripts_available += curr_script;
+    }
+    items_held = llGetInventoryNumber(INVENTORY_OBJECT);
+    for (indy = 0; indy < items_held; indy++) {
+        objects_available += llGetInventoryName(INVENTORY_OBJECT, indy);
+//log_it("added obj: " + llGetInventoryName(INVENTORY_OBJECT, indy));
+    }
+    items_held = llGetInventoryNumber(INVENTORY_NOTECARD);
+    for (indy = 0; indy < items_held; indy++) {
+        objects_available += llGetInventoryName(INVENTORY_NOTECARD, indy);
+//log_it("added note: " + llGetInventoryName(INVENTORY_NOTECARD, indy));
+    }
+
+    // listen to the owner.
+    llListen(USER_COMMAND_CHANNEL, "", llGetOwner(), "");
+    // listen for any requests from our loyal clients.
+    inventory_request_channel = random_channel();
+    llListen(inventory_request_channel, "", NULL_KEY, "");
+    // listen for older clients too.
+    llListen(OLD_REQUEST_INVENTORY_CHANNEL, "", NULL_KEY, "");
+
+    // set up the periodic announcements.
+    llSetTimerEvent(ANNOUNCEMENT_PERIOD);
+}
+
+handle_timer()
+{
+    if (dealing_with_change) {
+        dealing_with_change = FALSE;
+        state rerun;  // zoom back to the starting point.
+    }
+    integer indy;
+    integer timecheck = llGetUnixTime();  // use for whole loop.
+    for (indy = llGetListLength(active_timestamps) - 1; indy >= 0; indy--) {
+        integer last_time = llList2Integer(active_timestamps, indy);
+        if (llAbs(last_time - timecheck) > LONGEST_SLACK_PER_CLIENT) {
+            // we need to clear out this item.  we know we can whack the client
+            // at the same index and that will take care of this slacker.
+            key curr_key = llList2Key(active_clients, indy);
+            log_it("timed-out client: " + llKey2Name(curr_key) + " [" + (string)curr_key + "]");
+            remove_client(curr_key);
+        }
+    }
+
+    // let the objects nearby know that we are open for business by
+    // announcing the script inventory.
+    announce_presence();
+}
+
+// turns a list into a nicely formatted string.
+string dump_list(list to_show, integer initial_line_break, integer entries_per_line)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we break every Nth entry, but not if it's the first line and
+        // they said to not have the initial line break.
+        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
+            msg += "\n";
+        string cursc = llList2String(to_show, indy);
+        msg += cursc;
+        // add commas where needed.
+        if (indy < llGetListLength(to_show) - 1)
+            msg += ", ";
+    }
+    return msg;
+}
+
+// similar to dump_keyed_list, but only shows the names, each on their own line.
+string dump_names_for_keys(list to_show)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we only line break after the first entry.
+        if (indy > 0) msg += "\n";
+        string keystr = llList2String(to_show, indy);
+        msg += llKey2Name(keystr);
+    }
+    return msg;
+}
+
+// similar to dump_list
+string dump_keyed_list(list to_show, integer initial_line_break, integer entries_per_line)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we break every Nth entry, but not if it's the first line and
+        // they said to not have the initial line break.
+        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
+            msg += "\n";
+        string keystr = llList2String(to_show, indy);
+        msg += llKey2Name(keystr) + " (" + keystr + ")";
+        // add commas where needed.
+        if (indy < llGetListLength(to_show) - 1)
+            msg += ", ";
+    }
+    return msg;
+}
+
+// shows the list specified in a compact manner.
+show_list(string title, list to_show)
+{
+    string to_say = title + dump_list(to_show, TRUE, ENTRIES_PER_LINE);
+    // flush some memory.
+    title = "";
+    to_show = [];
+    integer indy;
+    // say the output in pieces to avoid over-clogging chat.
+    for (indy = 0; indy < llStringLength(to_say); indy += MESSAGE_SIZE_LIMIT) {
+        integer last_indy = indy + MESSAGE_SIZE_LIMIT - 1;
+        string addition;
+        if (last_indy < llStringLength(to_say)) addition = CONTINUANCE_MARKER;
+        llWhisper(0, llGetSubString(to_say, indy, last_indy) + addition);
+    }
+}
+
+// stops all the scripts besides this one.
+knock_down_other_scripts()
+{
+    // set all scripts but this to not be running.
+    integer indy;
+    string self_script = llGetScriptName();
+    list split = compute_basename_and_version(self_script);
+    string self_base = llList2String(split, 0);
+    self_script = ""; split = [];  // free memory.
+    integer count = llGetInventoryNumber(INVENTORY_SCRIPT);
+    // we set all other scripts that are not versions of this script to not be running.
+    for (indy = 0; indy < count; indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if (!is_prefix(curr_script, self_base)
+            && !is_prefix(curr_script, UPDATER_BASE_NAME) ) {
+            llSetScriptState(curr_script, FALSE);
+        }
+    }
+}
+
+// set a text label on the updater with the list of clients.
+set_our_label()
+{
+    string label = "";
+    if (llGetListLength(active_clients) > 0) label = "[updating]\n";
+    llSetText(label + dump_names_for_keys(active_clients), <0.8, 0.95, 0.92>, 1.0);
+}
+
+// clean out a client that we should be done with.
+remove_client(key id)
+{
+    // locate said client of deceased nature...
+    integer indy = find_in_list(active_clients, id);
+    if (indy < 0) {
+//        if (DEBUGGING) log_it("failure to find client to remove: " + (string)id);
+        return;
+    }
+    active_clients = llDeleteSubList(active_clients, indy, indy);
+    // also clean out the channel and stop listening to it.
+integer act_chan = llList2Integer(active_update_channels, indy);
+    active_update_channels = llDeleteSubList(active_update_channels, indy, indy);
+    integer listen_to_remove = llList2Integer(active_listen_ids, indy);
+//log_it("remove listen " + (string)listen_to_remove + " on chan " + (string)act_chan);
+    llListenRemove(listen_to_remove);
+    active_listen_ids = llDeleteSubList(active_listen_ids, indy, indy);
+    active_timestamps = llDeleteSubList(active_timestamps, indy, indy);
+    set_our_label();
+}
+
+// fix a partial match to a script name if we can't find the exact item.
+string backpatch_script_name(string partial)
+{
+    if (llGetInventoryType(partial) == INVENTORY_SCRIPT) return partial;  // all set.
+    integer dep_indy;
+    for (dep_indy = 0; dep_indy < llGetInventoryNumber(INVENTORY_SCRIPT); dep_indy++) {
+        string curr_name = llGetInventoryName(INVENTORY_SCRIPT, dep_indy);
+        if (is_prefix(curr_name, partial)) {
+//            log_it("found real name " + curr_name + " for part: " + partial);
+            return curr_name;
+        }
+    }
+//    log_it("no matches for partial script name!");
+    return "";  // no matches!
+}
+
+// moves the upgrade process with "id" along to the next step given the request in
+// the message.
+propel_upgrade_process(integer channel, key id, string message)
+{
+    if (DEBUGGING) log_it("got upgrade note from " + (string)id + " with msg=" + message);
+    if (message == REQUEST_SCRIPT_UPDATE) {
+        // begins the update process with the client.
+        llSay(channel, SHUT_THEM_DOWN);
+    } else if (is_prefix(message, READY_TO_UPDATE)) {
+        // whack the prefix so we can get the list they want.
+        message = llDeleteSubString(message, 0, llStringLength(READY_TO_UPDATE) - 1);
+        list requests = llParseString2List(message, [UPDATER_PARM_SEPARATOR], []);
+        message = "";
+        // send over the scripts the client asked for, since it seems to be ready for them.
+        if (llGetListLength(requests)) {
+            show_list("updating " + llKey2Name(id) + " (key " + (string)id + ") with", requests);
+            integer indy;
+            for (indy = 0; indy < llGetListLength(requests); indy++) {
+                string curr = llList2String(requests, indy);
+                if (find_in_list(objects_available, curr) >= 0) {
+//log_it("handing object over: " + curr);
+                    // it's an object, so treat it that way.
+                    llGiveInventory(id, curr);
+                } else {
+//log_it("handing script over: " + curr);
+                    // assume it's a script, and use script pin to stuff it.
+                    curr = backpatch_script_name(curr);
+                    if (curr != "") {
+//                        integer starting_state = FALSE;
+// second life was okay with scripts being plugged in unstarted.  opensim is not.
+// and second life appears to be unhappy with scripts plugged in as started.  so we
+// have an impasse.
+// this should be: true for opensim, and false for second life.
+                        integer starting_state = IS_OPENSIM;
+//                        if (DEBUGGING) log_it("installing script using updater pin.");
+                        llRemoteLoadScriptPin(id, curr, UPDATER_SCRIPT_PIN, starting_state, 0);
+                    }
+                }
+            }
+        }
+    } else if (message == SCRIPTS_ARE_CURRENT) {
+        // the client thinks it's ready to get back up and running.
+//log_it("heard client is ready!");
+        llSay(channel, START_THEM_UP);
+        // kludge for older clients (pre 10.4 version) to try to help them start up.
+//old and not useful.        llSleep(0.2); llSay(channel, START_THEM_UP); llSleep(0.2); llSay(channel, START_THEM_UP);
+        remove_client(id);
+    } else if (message == DONE_UPDATING) {
+        // this client has nothing to do for now.
+//log_it("heard client is done: " + (string)id);
+        remove_client(id);
+    } else {
+//log_it("weird note from client: " + message);
+        return;  // not used.
+    }
+    
+}
+
+// blasts out the inventory list to a curious client.
+spew_inventory_list(integer channel, string message, key id)
+{
+    if (!is_prefix(message, REQUEST_INVENTORY_PREFIX)) {
+
+        // this is an old style update alert that we still use at startup of the client
+        // to ensure that finishing replacement of the updater script is never unnoticed.
+        if (is_prefix(message, DONE_UPDATING)) {
+//            if (DEBUGGING) log_it("found very special message from startup of updater.");
+            propel_upgrade_process(channel, id, message);
+        }
+        
+        // argh, this is not the right kind of message on our channel.
+        return;
+    }
+    string chan_str = llDeleteSubString(message, 0, llStringLength(REQUEST_INVENTORY_PREFIX) - 1);
+    integer new_update_channel = (integer)chan_str;    
+    if (llGetListLength(active_clients) >= MAXIMUM_ACTIVE_CLIENTS) {
+        // got to tell them "not right now".  we'll pretend we have no
+        // scripts; they'll know what we mean if the update client is
+        // recent enough.  really old clients will just go to sleep until later.
+        if (DEBUGGING) log_it("having to disallow new client '" + llKey2Name(id) + "', too many now.");
+        llSay(new_update_channel, REPORT_AVAILABLE_SCRIPTS + BUSY_BUSY);
+        return;
+    }
+
+    // looks like we're going to try to handle the request for them.    
+    if (DEBUGGING) log_it("server heard update req on chan " + (string)channel + " from: " + llKey2Name(id));
+    
+//log_it("add client convo chan " + (string)new_update_channel);
+    integer existing_indy = find_in_list(active_clients, id);
+    if (existing_indy < 0) {
+        active_clients += id;
+        active_update_channels += new_update_channel;
+        integer new_listen_id = llListen(new_update_channel, "", id, "");
+//log_it("add listen " + (string)new_listen_id + " on chan " + (string)new_update_channel);
+        active_listen_ids += new_listen_id;
+        active_timestamps += llGetUnixTime();
+        set_our_label();
+    } else {
+//        if (DEBUGGING) log_it("same client came back before finishing previous upgrade, rolling with it.");
+        // delete old listener so we don't leave it dangling.
+        integer old_listen_id = llList2Integer(active_listen_ids, existing_indy);
+//log_it("remove old listen " + (string)old_listen_id);
+        llListenRemove(old_listen_id);
+        // update the channel and listener id for the new registration.
+        active_update_channels = chop_list(active_update_channels, 0, existing_indy - 1)
+            + [ new_update_channel ]
+            + chop_list(active_update_channels, existing_indy + 1,
+                llGetListLength(active_update_channels) - 1);
+        integer new_listen_id = llListen(new_update_channel, "", id, "");
+//log_it("add new listen " + (string)new_listen_id);
+        active_listen_ids = chop_list(active_listen_ids, 0, existing_indy - 1)
+            + [ new_listen_id ]
+            + chop_list(active_listen_ids, existing_indy + 1,
+                llGetListLength(active_listen_ids) - 1);
+        active_timestamps = chop_list(active_timestamps, 0, existing_indy - 1)
+            + [ new_listen_id ]
+            + chop_list(active_timestamps, existing_indy + 1,
+                llGetListLength(active_timestamps) - 1);
+    }
+
+    // our report name is always called available scripts, but it can actually have
+    // script dependency definitions, script names and object names.
+    string msg = REPORT_AVAILABLE_SCRIPTS;
+    string curr;  // temp.
+
+    // add in the huff updater, since that's the most crucial that they know we have.
+    integer posn;
+    string UPDATE_CLIENT_SCRIPT = "huff-update client";
+    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
+        curr = llList2String(scripts_available, posn);
+        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
+                == UPDATE_CLIENT_SCRIPT) {
+//log_it("found "  + curr);
+            msg += curr + UPDATER_PARM_SEPARATOR;
+            posn = 99999;  // jump out.
+        }
+        if (DEBUGGING && (posn == llGetListLength(scripts_available) - 1) ) {
+            log_it("epic fail, found no updater client script.");
+        }
+    }
+
+    // speak about the dependencies that we know.
+    for (posn = 0; posn < llGetListLength(known_script_dependencies); posn++) {
+        msg += SCRIPT_DEPENDENCY_MARK
+            + llList2String(known_script_dependencies, posn) + UPDATER_PARM_SEPARATOR;
+        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+            msg = REPORT_AVAILABLE_SCRIPTS;
+        }
+    }        
+    // tell this new client what scripts we have.
+    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
+        curr = llList2String(scripts_available, posn);
+        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
+                != UPDATE_CLIENT_SCRIPT) {            
+            // add in the next item, along with the parameter separator.
+            msg += curr + UPDATER_PARM_SEPARATOR;
+//log_it("adding " + curr);
+            if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+                llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+                if (channel == OLD_REQUEST_INVENTORY_CHANNEL) {
+                    // stop sending the list to them since they may not know how
+                    // to interpret a multiple part update list.
+                    return;
+                }
+                llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+                msg = REPORT_AVAILABLE_SCRIPTS;
+            }
+        }
+    }
+    // mention any objects that are available.
+    for (posn = 0; posn < llGetListLength(objects_available); posn++) {
+        // add in the next item, along with the parameter separator.            
+        msg += llList2String(objects_available, posn)
+            + UPDATER_PARM_SEPARATOR;
+        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+            msg = REPORT_AVAILABLE_SCRIPTS;
+        }
+    }
+    // say final bit, even if it's mostly blank.  we need to let them know
+    // that we're done and not adding that continuation flag string.
+    llSay(new_update_channel, msg);
+}
+
+// handles verbal commands from objects that want updates.
+process_verbal_requests(integer channel, string name, key id, string message)
+{
+    if ( (channel == OLD_REQUEST_INVENTORY_CHANNEL) || (channel == inventory_request_channel) ) {
+        spew_inventory_list(channel, message, id);
+        return;
+    } else if (channel == USER_COMMAND_CHANNEL) {
+if (DEBUGGING) log_it("heard orders: " + message);
+        // simple verbal commands.
+        if (message == RESTART_UPDATER_COMMAND) {
+            log_it("Restarting now.");
+            llResetScript();
+        } else if (message == SHOW_SCRIPTS_COMMAND) {
+            show_scripts();
+        } else if (message == SHUTDOWN_COMMAND) {
+            // we will de-rez now (i.e., die) if we are not one of the special names that is undying.
+            if (!matches_substring(llGetObjectName(), "keeper")) {
+//                log_it("server " + (string)inventory_request_channel + " now disintegrating.");
+                squonk(1);
+                llDie();
+            }
+        }
+        return;
+    }
+
+    integer indy;
+    // see if the channel is for one of our valid updates that's in progress.
+    for (indy = 0; indy < llGetListLength(active_update_channels); indy++) {
+        integer cur_chan = llList2Integer(active_update_channels, indy);
+        if (cur_chan == channel) {
+            // yes, this is really for that guy.
+            propel_upgrade_process(channel, id, message);
+            return;
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+//    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// a random channel for the first interaction with the client.
+integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+    
+    if (IS_OPENSIM && (llGetListLength(removal_list) > 0) ) {
+        log_it("now restarting to avoid opensim late updating change event.");
+        llResetScript();
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+    // thirdly, try to clean out the notecards.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.4.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+default
+{
+    state_entry()
+    {
+        auto_retire();
+        initialize_root();  // get set up to start answering requests.
+        llWhisper(0, llGetScriptName() + " started...  touch for more info.");
+        squonk(0);
+    }
+    
+    state_exit() { llSetTimerEvent(0); }
+
+    on_rez(integer parm) {
+        state rerun;
+    }
+
+    timer() { handle_timer(); }
+
+    touch_start(integer count) {
+        show_status(llDetectedKey(0));
+    }
+    
+    listen(integer channel, string name, key id, string message) {
+        // make sure that the object is something we should even talk to.
+        if (llGetOwnerKey(id) != llGetOwner()) {
+            return;
+        }
+        // looks okay, let's see if this is useful communication.
+        process_verbal_requests(channel, name, id, message); 
+    }
+
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            log_it("inventory changed, scheduled a restart.");
+            // sleep a little bit; otherwise we get SL noise about scripts not being
+            // there when it told us they were there.  this can lead to some scripts
+            // doing bizarre things if they are running when added.
+            dealing_with_change = TRUE;
+            llSetTimerEvent(0.0);  // kludge to get around second life bug.
+            llSetTimerEvent(CHANGED_INVENTORY_SNOOZER);
+        }
+    }
+}
+
+state rerun { state_entry() { state default; } }
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/a_huffotronic_update_server_v23.2.txt b/huffware/huffotronic_jaunter_updater_v5.1/a_huffotronic_update_server_v23.2.txt
deleted file mode 100755 (executable)
index ef201cf..0000000
+++ /dev/null
@@ -1,940 +0,0 @@
-
-// huffware script: huff-update server, by fred huffhines.
-//
-// this script is the server side of the update process.  it should reside in an object that
-// has all the newest versions of scripts and objects that will be updated.  when rezzed, and
-// at periodic intervals, it announces on a private chat channel that updates are available.
-// when objects respond that they might like an update, it tells them the scripts that it has
-// stored inside of it.  if any of those scripts are an older version inside the client
-// (update requesting) object, then the client will request the newer versions.  the server
-// object will stuff them into it and tell them to start running.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer IS_OPENSIM = TRUE;  // must be set to true for opensim, false for second life.
-
-integer DEBUGGING = FALSE;  // set this to true for noisier diagnostics.
-
-
-
-// updater dependency section:
-// should be moved to a notecard!!!
-//
-// format is a list of strings, where each string has a pair wrapped by the
-// huffware item separators.  the pair contains (1) the basename of a script
-// that has a new dependency and (2) the basename of that new dependency.
-list known_script_dependencies;
-
-
-
-
-load_script_deps()
-{
-    known_script_dependencies = [
-        llDumpList2String(["jaunt wik rez", "jaunt config funcs"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["jaunt wik rez", "data cow"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["jaunt wik rez", "jaunt rezolator"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["remotely personable", "inventory exchanger"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "exchange driver hudimation"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "avatar timer manager"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "avatar choice memory"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["giftorse", "particle projector"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["huff-search brainiac", "searchbert armature"], ITEM_LIST_SEPARATOR),
-
-        
-//special purpose -- removes the updater from the elevator buttons...
-//llDumpList2String(["comfortable sitting", "zap updater from elevators"], ITEM_LIST_SEPARATOR),
-// => do not uncomment unless you want your elevators to shed their ability to update.
-
-
-        // this allows us to add or remove items above at will without complaints about comma.
-        llDumpList2String(["xyzzy", "hopefully-never-matches"], ITEM_LIST_SEPARATOR)
-    ];
-}
-
-
-
-
-// global constants...
-
-integer USER_COMMAND_CHANNEL = 4;  // channel where we listen to user commands.
-
-float ANNOUNCEMENT_PERIOD = 14.0;  // how often we tell other objects that we have tasty treats.
-
-integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
-integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
-
-string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
-string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
-string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
-string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
-string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
-string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
-string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
-string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
-string DONE_UPDATING                = "#finito#";  // the client is done updating.
-string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
-
-integer UPDATER_SCRIPT_PIN          = -1231008;  // the hook for our scripts to be modified.
-
-string RESTART_UPDATER_COMMAND      = "#restart";  // said in open chat to recrank the updater.
-string SHOW_SCRIPTS_COMMAND         = "#show";  // said in open chat to list out the scripts.
-string SHUTDOWN_COMMAND             = "#destroy";  // shuts down object and destroys it.
-
-string UPDATER_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-
-string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
-
-integer ENTRIES_PER_LINE = 4;  // number of items from a list shown on one line of text.
-
-integer MAXIMUM_ACTIVE_CLIENTS = 5;  // number of conversations we will allow at a time.
-
-float LONGEST_SLACK_PER_CLIENT = 84.0;
-    // we allow a client to be out of touch with us for this many seconds.  after that,
-    // we decide it's deceased and remove it from our list.
-
-integer MESSAGE_SIZE_LIMIT = 800;  // longest thing that can be safely said without clipping (guess).
-
-float SCRIPT_LIST_PAUSE_INTERVAL = 1.4;  // pause between large chunks of update text.
-
-string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
-
-float CHANGED_INVENTORY_SNOOZER = 7.0;
-    // the number of seconds we sleep once we see an inventory change.  we don't want to
-    // react to this immediately.  this overrides the normal announcement cycle until it's
-    // dealt with by the timer.
-
-string CONTINUANCE_MARKER = "...";
-    // a string sent when the update list is too long and needs to be continued in another chat.
-
-string UPDATER_BASE_NAME = "huff-update client";
-    // the name of the updater script that keeps everything in sync.
-
-//////////////
-
-// global variables...
-
-list scripts_available;  // the list of scripts we have in our inventory for distribution.
-list objects_available;  // list of objects for handing out.
-
-list active_clients;  // list of keys for clients that are updating currently.
-list active_update_channels;  // active conversations on client chosen channels.
-list active_listen_ids;  // the ids for the listener on those channels.
-list active_timestamps;  // tracks when the client was last active.
-
-integer inventory_request_channel;  // our personal channel that the update client should talk with.
-
-integer dealing_with_change;  // has the inventory changed?  we will deal with this in the timer.
-
-// displays the status of the update server.
-show_status(key who_says)
-{
-    string title = "[mem free=" + (string)llGetFreeMemory() + "]";
-    title = "Listening for requests on channel " + (string)inventory_request_channel;
-    if (llGetListLength(active_update_channels))
-        title += "\nactive channels="
-            + dump_list(active_update_channels, FALSE, ENTRIES_PER_LINE);
-    else
-        title += "\nNo channels active.";
-        
-    if (llGetListLength(active_clients))
-        title += "\nactive clients=" + dump_keyed_list(active_clients, TRUE, 2);
-    else
-        title += "\nNo clients active.";
-    
-    if (llGetOwner() == who_says) {
-        string addition = " ";
-        if (USER_COMMAND_CHANNEL != 0) addition = "/" + (string)USER_COMMAND_CHANNEL + " ";
-        title += "\n[ \"" + addition + SHOW_SCRIPTS_COMMAND + "\" lists all the scripts, "
-            + "\"" + addition + SHUTDOWN_COMMAND + "\" zaps the updater, "
-            + "\"" + addition + RESTART_UPDATER_COMMAND + "\" refreshes the updater ]";
-    }
-
-    llWhisper(0, title);
-}
-
-// plink a quietous string of resonance...
-squonk(integer indy)
-{
-    string snd = llGetInventoryName(INVENTORY_SOUND, indy);
-    if (snd != "") llTriggerSound(snd, 1.0);
-}
-
-// list out the scripts that the server's object contains.
-show_scripts()
-{
-    string title = (string)llGetListLength(scripts_available) + " scripts available:";
-    show_list(title, scripts_available);
-    title = (string)llGetListLength(objects_available) + " objects available:";
-    show_list(title, objects_available);
-}
-
-// lets the client know that we're here and have some scripts available.
-announce_presence()
-{
-    if (llGetListLength(active_clients) < MAXIMUM_ACTIVE_CLIENTS) {
-        // only announce if we're not already booked up.
-        llWhisper(UPDATE_ANNOUNCEMENT_CHANNEL, UPDATE_ANNOUNCEMENT_PREFIX + (string)inventory_request_channel);
-    }
-}
-
-// lifted from "clear text and effects" script; should be nearly identical
-// to that, except that we set the texture animation.
-reset_all_effects()
-{
-    llSetText("", <0,0,0>, 0);  // clear any text above object.
-    llSetSitText("Sit Here");  // reset sit text to default state.
-    llSetTouchText("Touch");  // similarly for touch.
-    llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
-    llParticleSystem([]);  // turn off all particles.
-    llSensorRemove();  // stop any running sensors.
-    llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
-    llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
-    // keep it from being physical and from disapparating.
-    llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE,
-        PRIM_PHANTOM, TRUE]);
-    llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
-
-    //
-    // the following are specific to the huffotronic update server.
-    //
-
-    // we re-assert our special texture set here, in case some wayward scripts have
-    // messed with us.
-    integer textures_held = llGetInventoryNumber(INVENTORY_TEXTURE);
-    integer indy;
-    for (indy = 0; indy < textures_held; indy++) {
-        string curr_tex = llGetInventoryName(INVENTORY_TEXTURE, indy);
-        // we have a simple scheme for putting textures on the updater.
-        // we have an inside, an outside and the ends.
-        if (is_prefix(curr_tex, "~~s0")) {
-            llSetTexture(curr_tex, ALL_SIDES);
-        } else if (is_prefix(curr_tex, "~~s1")) {
-            llSetTexture(curr_tex, 1);
-        } else if (is_prefix(curr_tex, "~~s2")) {
-            llSetTexture(curr_tex, 0);
-            llSetTexture(curr_tex, 3);
-        }
-    }
-    
-    // re-assert our texture animation also.
-    llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE,
-        ALL_SIDES, 0, 0, 0, TWO_PI, 1.0 / 36.0);
-}
-
-// set up the update server object.
-initialize_root()
-{
-    // set up our particular "look".
-    reset_all_effects();
-
-    // shut down any competing scripts in this object.
-    // we try to swat any other script that's been added before we let them do weird
-    // stuff.  for example, a pet script might start acting like one.  this
-    // function is not guaranteed to run before that bad stuff can happen,
-    // and that's maybe the one major issue with this approach.  as long as
-    // the contained scripts aren't evil (like if they jump someplace else
-    // as soon as they start), then there shouldn't be any serious problems.
-    knock_down_other_scripts();
-
-    // reset our variables.
-    active_update_channels = [];
-    active_listen_ids = [];
-    active_clients = [];
-    active_timestamps = [];
-    scripts_available = [];
-    objects_available = [];
-    dealing_with_change = FALSE;  // not handling any inventory changes.
-
-    // make sure we know about any scripts that have new dependencies.
-    load_script_deps();
-
-    // clean out any older versions of the scripts before we make our
-    // inventory.
-    destroy_older_versions();
-
-    // now accumulate the list of scripts in our inventory.    
-    integer items_held = llGetInventoryNumber(INVENTORY_SCRIPT);
-    integer indy;
-    for (indy = 0; indy < items_held; indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        // we don't provide our own script for updating; it must be kept from
-        // floating around, like into other objects that are not updaters.
-////        if (curr_script != llGetScriptName())
-            scripts_available += curr_script;
-    }
-    items_held = llGetInventoryNumber(INVENTORY_OBJECT);
-    for (indy = 0; indy < items_held; indy++) {
-        objects_available += llGetInventoryName(INVENTORY_OBJECT, indy);
-//log_it("added obj: " + llGetInventoryName(INVENTORY_OBJECT, indy));
-    }
-    items_held = llGetInventoryNumber(INVENTORY_NOTECARD);
-    for (indy = 0; indy < items_held; indy++) {
-        objects_available += llGetInventoryName(INVENTORY_NOTECARD, indy);
-//log_it("added note: " + llGetInventoryName(INVENTORY_NOTECARD, indy));
-    }
-
-    // listen to the owner.
-    llListen(USER_COMMAND_CHANNEL, "", llGetOwner(), "");
-    // listen for any requests from our loyal clients.
-    inventory_request_channel = random_channel();
-    llListen(inventory_request_channel, "", NULL_KEY, "");
-    // listen for older clients too.
-    llListen(OLD_REQUEST_INVENTORY_CHANNEL, "", NULL_KEY, "");
-
-    // set up the periodic announcements.
-    llSetTimerEvent(ANNOUNCEMENT_PERIOD);
-}
-
-handle_timer()
-{
-    if (dealing_with_change) {
-        dealing_with_change = FALSE;
-        state rerun;  // zoom back to the starting point.
-    }
-    integer indy;
-    integer timecheck = llGetUnixTime();  // use for whole loop.
-    for (indy = llGetListLength(active_timestamps) - 1; indy >= 0; indy--) {
-        integer last_time = llList2Integer(active_timestamps, indy);
-        if (llAbs(last_time - timecheck) > LONGEST_SLACK_PER_CLIENT) {
-            // we need to clear out this item.  we know we can whack the client
-            // at the same index and that will take care of this slacker.
-            key curr_key = llList2Key(active_clients, indy);
-            log_it("timed-out client: " + llKey2Name(curr_key) + " [" + (string)curr_key + "]");
-            remove_client(curr_key);
-        }
-    }
-
-    // let the objects nearby know that we are open for business by
-    // announcing the script inventory.
-    announce_presence();
-}
-
-// turns a list into a nicely formatted string.
-string dump_list(list to_show, integer initial_line_break, integer entries_per_line)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we break every Nth entry, but not if it's the first line and
-        // they said to not have the initial line break.
-        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
-            msg += "\n";
-        string cursc = llList2String(to_show, indy);
-        msg += cursc;
-        // add commas where needed.
-        if (indy < llGetListLength(to_show) - 1)
-            msg += ", ";
-    }
-    return msg;
-}
-
-// similar to dump_keyed_list, but only shows the names, each on their own line.
-string dump_names_for_keys(list to_show)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we only line break after the first entry.
-        if (indy > 0) msg += "\n";
-        string keystr = llList2String(to_show, indy);
-        msg += llKey2Name(keystr);
-    }
-    return msg;
-}
-
-// similar to dump_list
-string dump_keyed_list(list to_show, integer initial_line_break, integer entries_per_line)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we break every Nth entry, but not if it's the first line and
-        // they said to not have the initial line break.
-        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
-            msg += "\n";
-        string keystr = llList2String(to_show, indy);
-        msg += llKey2Name(keystr) + " (" + keystr + ")";
-        // add commas where needed.
-        if (indy < llGetListLength(to_show) - 1)
-            msg += ", ";
-    }
-    return msg;
-}
-
-// shows the list specified in a compact manner.
-show_list(string title, list to_show)
-{
-    string to_say = title + dump_list(to_show, TRUE, ENTRIES_PER_LINE);
-    // flush some memory.
-    title = "";
-    to_show = [];
-    integer indy;
-    // say the output in pieces to avoid over-clogging chat.
-    for (indy = 0; indy < llStringLength(to_say); indy += MESSAGE_SIZE_LIMIT) {
-        integer last_indy = indy + MESSAGE_SIZE_LIMIT - 1;
-        string addition;
-        if (last_indy < llStringLength(to_say)) addition = CONTINUANCE_MARKER;
-        llWhisper(0, llGetSubString(to_say, indy, last_indy) + addition);
-    }
-}
-
-// stops all the scripts besides this one.
-knock_down_other_scripts()
-{
-    // set all scripts but this to not be running.
-    integer indy;
-    string self_script = llGetScriptName();
-    list split = compute_basename_and_version(self_script);
-    string self_base = llList2String(split, 0);
-    self_script = ""; split = [];  // free memory.
-    integer count = llGetInventoryNumber(INVENTORY_SCRIPT);
-    // we set all other scripts that are not versions of this script to not be running.
-    for (indy = 0; indy < count; indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if (!is_prefix(curr_script, self_base)
-            && !is_prefix(curr_script, UPDATER_BASE_NAME) ) {
-            llSetScriptState(curr_script, FALSE);
-        }
-    }
-}
-
-// set a text label on the updater with the list of clients.
-set_our_label()
-{
-    string label = "";
-    if (llGetListLength(active_clients) > 0) label = "[updating]\n";
-    llSetText(label + dump_names_for_keys(active_clients), <0.8, 0.95, 0.92>, 1.0);
-}
-
-// clean out a client that we should be done with.
-remove_client(key id)
-{
-    // locate said client of deceased nature...
-    integer indy = find_in_list(active_clients, id);
-    if (indy < 0) {
-//        if (DEBUGGING) log_it("failure to find client to remove: " + (string)id);
-        return;
-    }
-    active_clients = llDeleteSubList(active_clients, indy, indy);
-    // also clean out the channel and stop listening to it.
-integer act_chan = llList2Integer(active_update_channels, indy);
-    active_update_channels = llDeleteSubList(active_update_channels, indy, indy);
-    integer listen_to_remove = llList2Integer(active_listen_ids, indy);
-//log_it("remove listen " + (string)listen_to_remove + " on chan " + (string)act_chan);
-    llListenRemove(listen_to_remove);
-    active_listen_ids = llDeleteSubList(active_listen_ids, indy, indy);
-    active_timestamps = llDeleteSubList(active_timestamps, indy, indy);
-    set_our_label();
-}
-
-// fix a partial match to a script name if we can't find the exact item.
-string backpatch_script_name(string partial)
-{
-    if (llGetInventoryType(partial) == INVENTORY_SCRIPT) return partial;  // all set.
-    integer dep_indy;
-    for (dep_indy = 0; dep_indy < llGetInventoryNumber(INVENTORY_SCRIPT); dep_indy++) {
-        string curr_name = llGetInventoryName(INVENTORY_SCRIPT, dep_indy);
-        if (is_prefix(curr_name, partial)) {
-//            log_it("found real name " + curr_name + " for part: " + partial);
-            return curr_name;
-        }
-    }
-//    log_it("no matches for partial script name!");
-    return "";  // no matches!
-}
-
-// moves the upgrade process with "id" along to the next step given the request in
-// the message.
-propel_upgrade_process(integer channel, key id, string message)
-{
-    if (DEBUGGING) log_it("got upgrade note from " + (string)id + " with msg=" + message);
-    if (message == REQUEST_SCRIPT_UPDATE) {
-        // begins the update process with the client.
-        llSay(channel, SHUT_THEM_DOWN);
-    } else if (is_prefix(message, READY_TO_UPDATE)) {
-        // whack the prefix so we can get the list they want.
-        message = llDeleteSubString(message, 0, llStringLength(READY_TO_UPDATE) - 1);
-        list requests = llParseString2List(message, [UPDATER_PARM_SEPARATOR], []);
-        message = "";
-        // send over the scripts the client asked for, since it seems to be ready for them.
-        if (llGetListLength(requests)) {
-            show_list("updating " + llKey2Name(id) + " (key " + (string)id + ") with", requests);
-            integer indy;
-            for (indy = 0; indy < llGetListLength(requests); indy++) {
-                string curr = llList2String(requests, indy);
-                if (find_in_list(objects_available, curr) >= 0) {
-//log_it("handing object over: " + curr);
-                    // it's an object, so treat it that way.
-                    llGiveInventory(id, curr);
-                } else {
-//log_it("handing script over: " + curr);
-                    // assume it's a script, and use script pin to stuff it.
-                    curr = backpatch_script_name(curr);
-                    if (curr != "") {
-//                        integer starting_state = FALSE;
-// second life was okay with scripts being plugged in unstarted.  opensim is not.
-// and second life appears to be unhappy with scripts plugged in as started.  so we
-// have an impasse.
-// this should be: true for opensim, and false for second life.
-                        integer starting_state = IS_OPENSIM;
-//                        if (DEBUGGING) log_it("installing script using updater pin.");
-                        llRemoteLoadScriptPin(id, curr, UPDATER_SCRIPT_PIN, starting_state, 0);
-                    }
-                }
-            }
-        }
-    } else if (message == SCRIPTS_ARE_CURRENT) {
-        // the client thinks it's ready to get back up and running.
-//log_it("heard client is ready!");
-        llSay(channel, START_THEM_UP);
-        // kludge for older clients (pre 10.4 version) to try to help them start up.
-//old and not useful.        llSleep(0.2); llSay(channel, START_THEM_UP); llSleep(0.2); llSay(channel, START_THEM_UP);
-        remove_client(id);
-    } else if (message == DONE_UPDATING) {
-        // this client has nothing to do for now.
-//log_it("heard client is done: " + (string)id);
-        remove_client(id);
-    } else {
-//log_it("weird note from client: " + message);
-        return;  // not used.
-    }
-    
-}
-
-// blasts out the inventory list to a curious client.
-spew_inventory_list(integer channel, string message, key id)
-{
-    if (!is_prefix(message, REQUEST_INVENTORY_PREFIX)) {
-
-        // this is an old style update alert that we still use at startup of the client
-        // to ensure that finishing replacement of the updater script is never unnoticed.
-        if (is_prefix(message, DONE_UPDATING)) {
-//            if (DEBUGGING) log_it("found very special message from startup of updater.");
-            propel_upgrade_process(channel, id, message);
-        }
-        
-        // argh, this is not the right kind of message on our channel.
-        return;
-    }
-    string chan_str = llDeleteSubString(message, 0, llStringLength(REQUEST_INVENTORY_PREFIX) - 1);
-    integer new_update_channel = (integer)chan_str;    
-    if (llGetListLength(active_clients) >= MAXIMUM_ACTIVE_CLIENTS) {
-        // got to tell them "not right now".  we'll pretend we have no
-        // scripts; they'll know what we mean if the update client is
-        // recent enough.  really old clients will just go to sleep until later.
-        if (DEBUGGING) log_it("having to disallow new client '" + llKey2Name(id) + "', too many now.");
-        llSay(new_update_channel, REPORT_AVAILABLE_SCRIPTS + BUSY_BUSY);
-        return;
-    }
-
-    // looks like we're going to try to handle the request for them.    
-    if (DEBUGGING) log_it("server heard update req on chan " + (string)channel + " from: " + llKey2Name(id));
-    
-//log_it("add client convo chan " + (string)new_update_channel);
-    integer existing_indy = find_in_list(active_clients, id);
-    if (existing_indy < 0) {
-        active_clients += id;
-        active_update_channels += new_update_channel;
-        integer new_listen_id = llListen(new_update_channel, "", id, "");
-//log_it("add listen " + (string)new_listen_id + " on chan " + (string)new_update_channel);
-        active_listen_ids += new_listen_id;
-        active_timestamps += llGetUnixTime();
-        set_our_label();
-    } else {
-//        if (DEBUGGING) log_it("same client came back before finishing previous upgrade, rolling with it.");
-        // delete old listener so we don't leave it dangling.
-        integer old_listen_id = llList2Integer(active_listen_ids, existing_indy);
-//log_it("remove old listen " + (string)old_listen_id);
-        llListenRemove(old_listen_id);
-        // update the channel and listener id for the new registration.
-        active_update_channels = chop_list(active_update_channels, 0, existing_indy - 1)
-            + [ new_update_channel ]
-            + chop_list(active_update_channels, existing_indy + 1,
-                llGetListLength(active_update_channels) - 1);
-        integer new_listen_id = llListen(new_update_channel, "", id, "");
-//log_it("add new listen " + (string)new_listen_id);
-        active_listen_ids = chop_list(active_listen_ids, 0, existing_indy - 1)
-            + [ new_listen_id ]
-            + chop_list(active_listen_ids, existing_indy + 1,
-                llGetListLength(active_listen_ids) - 1);
-        active_timestamps = chop_list(active_timestamps, 0, existing_indy - 1)
-            + [ new_listen_id ]
-            + chop_list(active_timestamps, existing_indy + 1,
-                llGetListLength(active_timestamps) - 1);
-    }
-
-    // our report name is always called available scripts, but it can actually have
-    // script dependency definitions, script names and object names.
-    string msg = REPORT_AVAILABLE_SCRIPTS;
-    string curr;  // temp.
-
-    // add in the huff updater, since that's the most crucial that they know we have.
-    integer posn;
-    string UPDATE_CLIENT_SCRIPT = "huff-update client";
-    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
-        curr = llList2String(scripts_available, posn);
-        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
-                == UPDATE_CLIENT_SCRIPT) {
-//log_it("found "  + curr);
-            msg += curr + UPDATER_PARM_SEPARATOR;
-            posn = 99999;  // jump out.
-        }
-        if (DEBUGGING && (posn == llGetListLength(scripts_available) - 1) ) {
-            log_it("epic fail, found no updater client script.");
-        }
-    }
-
-    // speak about the dependencies that we know.
-    for (posn = 0; posn < llGetListLength(known_script_dependencies); posn++) {
-        msg += SCRIPT_DEPENDENCY_MARK
-            + llList2String(known_script_dependencies, posn) + UPDATER_PARM_SEPARATOR;
-        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-            msg = REPORT_AVAILABLE_SCRIPTS;
-        }
-    }        
-    // tell this new client what scripts we have.
-    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
-        curr = llList2String(scripts_available, posn);
-        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
-                != UPDATE_CLIENT_SCRIPT) {            
-            // add in the next item, along with the parameter separator.
-            msg += curr + UPDATER_PARM_SEPARATOR;
-//log_it("adding " + curr);
-            if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-                llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-                if (channel == OLD_REQUEST_INVENTORY_CHANNEL) {
-                    // stop sending the list to them since they may not know how
-                    // to interpret a multiple part update list.
-                    return;
-                }
-                llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-                msg = REPORT_AVAILABLE_SCRIPTS;
-            }
-        }
-    }
-    // mention any objects that are available.
-    for (posn = 0; posn < llGetListLength(objects_available); posn++) {
-        // add in the next item, along with the parameter separator.            
-        msg += llList2String(objects_available, posn)
-            + UPDATER_PARM_SEPARATOR;
-        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-            msg = REPORT_AVAILABLE_SCRIPTS;
-        }
-    }
-    // say final bit, even if it's mostly blank.  we need to let them know
-    // that we're done and not adding that continuation flag string.
-    llSay(new_update_channel, msg);
-}
-
-// handles verbal commands from objects that want updates.
-process_verbal_requests(integer channel, string name, key id, string message)
-{
-    if ( (channel == OLD_REQUEST_INVENTORY_CHANNEL) || (channel == inventory_request_channel) ) {
-        spew_inventory_list(channel, message, id);
-        return;
-    } else if (channel == USER_COMMAND_CHANNEL) {
-if (DEBUGGING) log_it("heard orders: " + message);
-        // simple verbal commands.
-        if (message == RESTART_UPDATER_COMMAND) {
-            log_it("Restarting now.");
-            llResetScript();
-        } else if (message == SHOW_SCRIPTS_COMMAND) {
-            show_scripts();
-        } else if (message == SHUTDOWN_COMMAND) {
-            // we will de-rez now (i.e., die) if we are not one of the special names that is undying.
-            if (!matches_substring(llGetObjectName(), "keeper")) {
-//                log_it("server " + (string)inventory_request_channel + " now disintegrating.");
-                squonk(1);
-                llDie();
-            }
-        }
-        return;
-    }
-
-    integer indy;
-    // see if the channel is for one of our valid updates that's in progress.
-    for (indy = 0; indy < llGetListLength(active_update_channels); indy++) {
-        integer cur_chan = llList2Integer(active_update_channels, indy);
-        if (cur_chan == channel) {
-            // yes, this is really for that guy.
-            propel_upgrade_process(channel, id, message);
-            return;
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-//    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// a random channel for the first interaction with the client.
-integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-    
-    if (IS_OPENSIM && (llGetListLength(removal_list) > 0) ) {
-        log_it("now restarting to avoid opensim late updating change event.");
-        llResetScript();
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-    // thirdly, try to clean out the notecards.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.4.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-default
-{
-    state_entry()
-    {
-        auto_retire();
-        initialize_root();  // get set up to start answering requests.
-        llWhisper(0, llGetScriptName() + " started...  touch for more info.");
-        squonk(0);
-    }
-    
-    state_exit() { llSetTimerEvent(0); }
-
-    on_rez(integer parm) {
-        state rerun;
-    }
-
-    timer() { handle_timer(); }
-
-    touch_start(integer count) {
-        show_status(llDetectedKey(0));
-    }
-    
-    listen(integer channel, string name, key id, string message) {
-        // make sure that the object is something we should even talk to.
-        if (llGetOwnerKey(id) != llGetOwner()) {
-            return;
-        }
-        // looks okay, let's see if this is useful communication.
-        process_verbal_requests(channel, name, id, message); 
-    }
-
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            log_it("inventory changed, scheduled a restart.");
-            // sleep a little bit; otherwise we get SL noise about scripts not being
-            // there when it told us they were there.  this can lead to some scripts
-            // doing bizarre things if they are running when added.
-            dealing_with_change = TRUE;
-            llSetTimerEvent(0.0);  // kludge to get around second life bug.
-            llSetTimerEvent(CHANGED_INVENTORY_SNOOZER);
-        }
-    }
-}
-
-state rerun { state_entry() { state default; } }
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/child_jaunter_v85.2.lsl b/huffware/huffotronic_jaunter_updater_v5.1/child_jaunter_v85.2.lsl
new file mode 100755 (executable)
index 0000000..76465b7
--- /dev/null
@@ -0,0 +1,679 @@
+
+// huffware script: child jaunter, by fred huffhines,  released under GPL license.
+//
+// this is the sub-jaunter implementation, for children of a root jaunter.  this script
+// handles reconnaissance and one-way trips.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+
+// configurable constants...
+
+string TEXT_COLOR = "<0.5, 0.7, 0.95>";
+    // set float text color to a nice color.
+
+integer DEBUGGING = FALSE;
+    // set to true to get debugging noises.
+
+// requires jaunting library API.
+//////////////
+// do not redefine these constants.
+integer JAUNT_HUFFWARE_ID = 10008;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+// commands available via the jaunting library:
+string FULL_STOP_COMMAND = "#fullstop#";
+    // command used to bring object to a halt.
+string JAUNT_LIST_COMMAND = "#jauntlist#";
+    // like regular jaunt, but expects a string in jaunt notecard format with vectors.
+    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
+//
+//////////////
+
+// the API for this library script to be used in other scripts.
+//////////////
+// do not redefine these constants.
+integer JAUNT_REZOLATOR_HUFFWARE_ID = 10025;
+    // the unique id within the huffware system for this script's commands.
+    // it's used in llMessageLinked as the num parameter.
+//////////////
+// commands available from the library:
+string RESET_REZOLATOR = "#reset";
+    // tells the script to stop any previous efforts to rez children.
+//string REZ_CHILD_NOW = "#rezkd#";
+    // requests this script to create a new child object.  this requires several
+    // parameters to succeed: 1) object to rez, 2) conveyance mode for the rezzed object
+    // to implement, 3) the chat channel to listen for and speak to new child on,
+    // 4) the destination name for where the child should go, 5) a count of the full
+    // set of known destinations, 6) the target where the jaunt should arrive at.
+string REPORT_CHILD_REZZED = "#reziam";
+    // requests that this class report to the root jaunter that a child has rezzed and
+    // is ready for service.  there are no required parameters.
+string REZOLATOR_CHILD_SUPPORT = "#rzsup";
+    // used by child jaunters to request that the rezolator handle things for them.
+string REZOLATOR_CHILD_RETURNED = "#rezdon";
+    // used by the child jaunter to tell the rezolator that it has jumped to wherever it
+    // was supposed to and is ready to report to the parent, if needed.  the first parameter
+    // required for the rezolator is whether the jump was successful (1) or not (0), and
+    // the second parameter should be the last safe position that the jaunter was at when
+    // it was possibly closest to the target.
+//////////////
+// events generated by the library:
+//string REZOLATOR_EVENT_REZZED_CHILD = "#donekd";
+    // an event generated for a previous rez child request.  this lets the caller know that
+    // the child has been created and told what to do.  the single parameter is where the
+    // jaunter has been rezzed.
+string REZOLATOR_EVENT_GOT_INSTRUCTIONS = "#rzsta";
+    // the root jaunter has given a child instructions on where to go.  this info includes
+    // the name of the destination, the pathway to get there, and the conveyance mode.
+//string REZOLATOR_EVENT_RECON_FINISHED = "#rzcnfn";
+    // an event generated when the recon process has concluded.  this includes parms:
+    // number of good destinations.
+//
+//////////////
+
+// important constants used internally...  these should not be changed willy nilly.
+
+////////////// jaunt base API
+
+// the following constants define how the script should behave (i.e., its conveyance mode).
+// TWO_WAY_TRIP: the script jaunts using the current target vectors to get somewhere
+//   and then takes the same pathway back, but in reverse order.
+// AUTOREZ_JAUNTER: the script rezzes the first regular object in its inventory next to
+//   the root telehub.  that object is loaded with the destination notecard and this script.
+//   the rezzed object can then be used for the next few minutes to jaunt to the selected
+//   destination.  the temporary object will use the ONE_WAY_TRIP mode.
+// ONE_WAY_TRIP: the object containing this script will take the user to a particular
+//   destination, but the object does not survive the trip.  it self-destructs after
+//   reaching the destination.  this mode is used in conjunction with the AUTOREZ_JAUNTER
+//   mode and should generally never be used on its own.
+// RECONNAISSANCE_TRIP: a survey run to test out a particular path to get to a
+//   destination.
+integer TWO_WAY_TRIP = 1;
+integer AUTOREZ_JAUNTER = 2;
+integer ONE_WAY_TRIP = 3;
+integer RECONNAISSANCE_TRIP = 4;
+
+// values used to represent different stages of verification.
+integer VERIFY_UNTESTED = -3;  // don't know destinations tate yet.
+integer VERIFY_SAFE = -4;  // the destination last tested safe.
+integer VERIFY_UNSAFE_SO_FAR = -5;  // this cannot be done with simple jaunt.
+integer VERIFY_UNSAFE_DECIDED = -6;  // this means the destination seems intractable.
+
+integer MAXIMUM_PRIV_CHAN = 90000;
+    // the largest amount we will ever subtract from the tricky parms in order to
+    // tell the sub-jaunter which channel to listen on.
+
+string VECTOR_SEPARATOR = "|";
+    // how we separate components of vectors from each other.
+string DB_SEPARATOR = "``";  // separating items in lists.
+
+////////////// end jaunt base API
+
+integer MAX_DEST_NAME = 24;  // the longest name that we store.
+
+float NORMAL_TIMER_PERIOD = 1.0;  // our normal timer rate.
+
+float POSITION_CHECKING_INTERVAL = 0.11;
+    // how frequently the waiting for arrival state will check where we are.
+
+integer MAXIMUM_SLACKNESS = 108;
+    // how many timer hits we'll allow before reverting to the default state.
+
+integer FREE_MEM_REQUIRED = 3200;
+    // we need at least this much memory before adding new targets.
+
+//////////////
+
+// global variables.
+
+integer startup_parm;  // recorded at rez time.  used for deciding what to do.
+
+integer conveyance_mode;  // when we are given our instructions, we will know what type of jump to use.
+
+// jaunter target configuration...
+string global_name;  // the name for our destination.
+integer global_verification_state;  // the verification state of the last destination we asked for.
+string global_pathway;  // similar, but the last pathway we heard.
+
+// jaunt trip variables...
+vector eventual_destination;  // where we're headed, if we're headed anywhere.
+integer slackness_counter;  // snoozes had while waiting for destination.
+list full_journey;  // the full pathway we expect to jaunt on.
+integer jaunt_responses_awaited;  // number of pending jumps in progress.
+integer got_close_enough;  // did we arrive at right place?
+vector last_safe_position;  // where did we actually reach?
+
+// asks the jaunting library to take us to the target using a list of waypoints.
+request_jaunt(list journey, integer forwards)
+{
+    // ask for a jump.
+    jaunt_responses_awaited++;
+    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_LIST_COMMAND,
+        wrap_item_list(journey) + HUFFWARE_PARM_SEPARATOR + (string)forwards);
+    // stops the jaunter in its tracks.
+    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, FULL_STOP_COMMAND, ""); 
+}
+
+// this function returns TRUE if we are close enough to the "destination".
+integer close_enough(vector destination)
+{
+    float PROXIMITY_REQUIRED = 0.1;
+        // how close we must be to the target location to call it done.
+        // matches current jaunting library proximity.
+    return (llVecDist(llGetPos(), destination) <= PROXIMITY_REQUIRED);
+}
+
+// sets up the initial state.
+initialize_child()
+{
+    llSetTimerEvent(0.0);  // cancel any existing timers.
+    // load up an arrival sound if any exist.
+    if (llGetInventoryNumber(INVENTORY_SOUND))
+        llPreloadSound(llGetInventoryName(INVENTORY_SOUND, 0));
+    if (DEBUGGING) log_it("child init startparm=" + (string)startup_parm);
+
+//voodoo.
+    llSleep(0.5);
+    
+    if (startup_parm != 0) {
+        // tell the rezolator to start listening for commands.
+        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZOLATOR_CHILD_SUPPORT,
+            wrap_parameters([startup_parm]));
+        // let our parent know we're here.
+        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REPORT_CHILD_REZZED, "");
+    }
+    // set up some of the object properties...
+    llSetSitText("Jaunt");  // change to the proper text for our mode.
+}
+
+// shows our next target for jaunting above the object.
+text_label_for_destination()
+{
+    string msg = "↣ " + global_name;
+    llSetText(msg, (vector)TEXT_COLOR, 1.0);
+}
+
+// signal that we are where we were going.
+proclaim_arrival()
+{
+    if (conveyance_mode == ONE_WAY_TRIP) {
+        // sing a little song, if there's a sound to use.
+        if (llGetInventoryNumber(INVENTORY_SOUND))
+            llTriggerSound(llGetInventoryName(INVENTORY_SOUND, 0), 1.0);
+    }
+}
+
+string verification_name(integer enumtype)
+{
+    if (enumtype == VERIFY_SAFE) return "ok";
+    else if (enumtype == VERIFY_UNSAFE_SO_FAR) return "uhh";
+    else if (enumtype == VERIFY_UNSAFE_DECIDED) return "far";
+    // catch-all, including untested.
+    return "?";
+}
+
+// returns true if the slackness counter awaiting things has elapsed.
+integer check_for_timeout()
+{
+    if (slackness_counter++ > MAXIMUM_SLACKNESS) {
+        // go back to the main state.  we took too long.
+        log_it("timed out!");
+        llUnSit(llAvatarOnSitTarget());  // don't hang onto the avatar for this error.
+        llSetTimerEvent(0.0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+//////////////
+
+// returns the value of a boolean variable definition.
+integer parse_bool_def(string def)
+{ return !(llGetSubString(def, find_substring(def, "=") + 1, -1) == "0"); }
+
+// processes link messages received from support libraries.
+integer handle_link_message(integer which, integer num, string msg, string id)
+{
+    // is it a jaunting library response?
+    if (num == JAUNT_HUFFWARE_ID + REPLY_DISTANCE) {
+        jaunt_responses_awaited--;  // one less response being awaited.
+        if (jaunt_responses_awaited < 0) {
+            log_it("error: responses awaited < 0");
+            jaunt_responses_awaited = 0;
+        }
+        return FALSE;
+    }
+    
+    // is it an event from the rezolator script?
+    if (num == JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        if (msg == REZOLATOR_EVENT_GOT_INSTRUCTIONS) {
+            global_name = llList2String(parms, 0);
+            full_journey = [ llGetPos() ] + llParseString2List(llList2String(parms, 1), [VECTOR_SEPARATOR], []);
+            eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
+            conveyance_mode = llList2Integer(parms, 2);
+            if (DEBUGGING)
+                log_it("got instructions: name=" + global_name + " dest=" + (string)eventual_destination);
+            text_label_for_destination();
+            if (conveyance_mode == RECONNAISSANCE_TRIP) {
+                return TRUE;
+            }
+        }
+        return FALSE;
+    }
+
+    return FALSE;
+}
+
+// processes a destination set to handle special cases, like for offset jaunting.
+list prechewed_destinations(string dests)
+{
+
+//document this!!!
+// as in, we support the offset format!
+
+    // look for our special start character for offsets.
+    if (is_prefix(dests, "o"))
+        // if this is an offset version, then chop whatever word they used starting with 'o'
+        // and compute the destination based on current position.
+        return [ (vector)llDeleteSubString(dests, 0, find_substring(dests, "<") - 1) + llGetPos() ];
+    else
+        // normal jaunt to absolute coordinates.
+        return llParseString2List(dests, [VECTOR_SEPARATOR], []);
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+///////////////
+
+// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
+integer valid_sim_value(float to_check)
+{
+    if (to_check < 0.0) return FALSE;
+    if (to_check >= 257.0) return FALSE;
+    return TRUE;
+}
+
+// returns TRUE if the "to_check" vector is a location outside of the current sim.
+integer outside_of_sim(vector to_check)
+{
+    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
+}
+
+// returns text for a floating point number, but includes only
+// two digits after the decimal point.
+string float_chop(float to_show)
+{
+    integer mant = llAbs(llRound(to_show * 100.0) / 100);
+    string neg_sign;
+    if (to_show < 0.0) neg_sign = "-";
+    string dec_s = (string)((llRound(to_show * 100.0) - mant * 100) / 100.0);
+    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
+    // strip off all trailing zeros.
+    while (llGetSubString(dec_s, -1, -1) == "0")
+        dec_s = llDeleteSubString(dec_s, -1, -1);
+    string to_return = neg_sign + (string)mant;
+    if (llStringLength(dec_s)) to_return += "." + dec_s;
+    return to_return;
+}
+
+// returns a prettier form for vector text, with chopped floats.
+string vector_chop(vector to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ">";
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{
+    string full_lower = llToLower(full_string);
+    return llSubStringIndex(full_lower, pattern);
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//////////////
+
+// default state scrounges for information in a notecard and looks for landmarks in
+// inventory to add as destinations.
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) {
+        startup_parm = parm; 
+        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
+        state rerun;
+    }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        if (DEBUGGING) log_it("=> real_default state, mem=" + (string)llGetFreeMemory());
+        initialize_child();
+        state normal_runtime;
+    }
+    
+    on_rez(integer parm) {
+        startup_parm = parm; 
+        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
+        state default;
+    }
+}
+
+// the normal state is pretty calm; the jaunter just sits there waiting for
+// an avatar who needs it to do something.
+state normal_runtime
+{
+    state_entry() {
+        if (DEBUGGING) log_it("=> normal state, mem=" + (string)llGetFreeMemory());
+        jaunt_responses_awaited = 0;  // nothing pending right now.
+        got_close_enough = FALSE;  // have not even tried going there yet.
+    }
+
+    on_rez(integer parm) {
+        startup_parm = parm;
+        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
+        state default;
+    }
+
+    touch_end(integer total_number) {
+        // if we got to here, we may need to check the safety of the target and show the
+        // map if the conditions are right.
+        if (outside_of_sim(eventual_destination)) {
+            // bring up the map; maybe we can't get there from here.  definitely out of sim.
+            llMapDestination(llGetRegionName(), eventual_destination, ZERO_VECTOR);
+            proclaim_arrival();
+        }
+    }
+
+    changed(integer change) {
+        if (!(change & CHANGED_LINK)) return;  // don't care then.
+//no, bad, ack.  if the jaunter has multiple parts and they sit on non-root prim, this breaks our ability to react to sit events properly.        if (llAvatarOnSitTarget() == NULL_KEY) return;  // there is no one sitting now.
+        if (outside_of_sim(eventual_destination)) {
+            llWhisper(0, "This type of jaunter needs to be clicked rather than sat upon.  Please left-click it (or right-click it and select 'touch').");
+            llUnSit(llAvatarOnSitTarget());
+            return;
+        }
+        state jaunting_now;  // sweet, we're off.
+    }
+
+    // process the response from the APIs we use.
+    link_message(integer which, integer num, string msg, key id) {
+        if (handle_link_message(which, num, msg, id)) state jaunting_now;
+    }
+    
+}
+
+// once someone is trying to jump to a target, this state processes the request.
+state jaunting_now
+{
+    state_entry() {
+        if (DEBUGGING) log_it("=> jauntnow state, posn=" + vector_chop(llGetPos()));
+        slackness_counter = 0;
+        // most jaunters go to at least the first location...
+        request_jaunt(full_journey, TRUE);
+        eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
+        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+    }
+
+    on_rez(integer parm)
+    {
+        startup_parm = parm;
+        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
+        state default;
+    }
+
+    timer() {
+        if (jaunt_responses_awaited) {
+            // we are not quite there yet.
+            if (check_for_timeout()) state normal_runtime;  // oops.
+            return;  // not time yet.
+        }
+        // we got to where we were going, maybe.  unseat the avatar, leaving her
+        // at the destination.
+        llUnSit(llAvatarOnSitTarget());
+        state arrived_at_target;
+    }
+
+    // process the response from the jaunting library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+}
+
+// this state is activated when the first jaunt is complete.
+state arrived_at_target
+{
+    state_entry() {
+        if (DEBUGGING) log_it("=> arriv targ state, posn=" + vector_chop(llGetPos()));
+        // we are close enough; get back to work.
+        jaunt_responses_awaited = 0;  // nothing pending right now.
+        if (conveyance_mode != RECONNAISSANCE_TRIP) {
+            llWhisper(0, "↣ " + global_name);
+        } else {
+            if (DEBUGGING) {
+                string close = "yep";
+                if (!close_enough(eventual_destination)) close = "nope";
+                log_it("close enough here? " + close + ", want to get to "
+                    + (string)eventual_destination);
+            }
+            got_close_enough = close_enough(eventual_destination);
+            last_safe_position = llGetPos();
+        }
+
+        // we've gotten where we were going.
+        proclaim_arrival();
+
+//hmmm: nice mod to make the one way trip actually flip its target list and allow a return.
+
+        // reverse direction and head back without rider.
+        eventual_destination = (vector)llList2String(full_journey, 0);
+        request_jaunt(full_journey, FALSE);
+        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+        slackness_counter = 0;
+        if (DEBUGGING) log_it("now trying to jaunt home, responses awaited=" + (string)jaunt_responses_awaited);
+    }
+
+    on_rez(integer parm) {
+        startup_parm = parm; 
+        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
+        state default;
+    }
+
+    timer() {
+        if (jaunt_responses_awaited) {
+            // we are not quite there yet.
+            if (check_for_timeout()) state normal_runtime;  // oops.
+            return;  // not time yet.
+        }
+        if (DEBUGGING) log_it("==> telling parent we got back, now at posn: " + (string)llGetPos());
+        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZOLATOR_CHILD_RETURNED,
+            wrap_parameters([got_close_enough, 
+                llDumpList2String(llDeleteSubList(full_journey, 0, 0) + [ last_safe_position ],
+                    VECTOR_SEPARATOR)]));
+        state normal_runtime;
+    }
+    
+    // process the response from the jaunting library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); } 
+}
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/child_jaunter_v85.2.txt b/huffware/huffotronic_jaunter_updater_v5.1/child_jaunter_v85.2.txt
deleted file mode 100755 (executable)
index 76465b7..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-
-// huffware script: child jaunter, by fred huffhines,  released under GPL license.
-//
-// this is the sub-jaunter implementation, for children of a root jaunter.  this script
-// handles reconnaissance and one-way trips.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-
-// configurable constants...
-
-string TEXT_COLOR = "<0.5, 0.7, 0.95>";
-    // set float text color to a nice color.
-
-integer DEBUGGING = FALSE;
-    // set to true to get debugging noises.
-
-// requires jaunting library API.
-//////////////
-// do not redefine these constants.
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-// commands available via the jaunting library:
-string FULL_STOP_COMMAND = "#fullstop#";
-    // command used to bring object to a halt.
-string JAUNT_LIST_COMMAND = "#jauntlist#";
-    // like regular jaunt, but expects a string in jaunt notecard format with vectors.
-    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
-//
-//////////////
-
-// the API for this library script to be used in other scripts.
-//////////////
-// do not redefine these constants.
-integer JAUNT_REZOLATOR_HUFFWARE_ID = 10025;
-    // the unique id within the huffware system for this script's commands.
-    // it's used in llMessageLinked as the num parameter.
-//////////////
-// commands available from the library:
-string RESET_REZOLATOR = "#reset";
-    // tells the script to stop any previous efforts to rez children.
-//string REZ_CHILD_NOW = "#rezkd#";
-    // requests this script to create a new child object.  this requires several
-    // parameters to succeed: 1) object to rez, 2) conveyance mode for the rezzed object
-    // to implement, 3) the chat channel to listen for and speak to new child on,
-    // 4) the destination name for where the child should go, 5) a count of the full
-    // set of known destinations, 6) the target where the jaunt should arrive at.
-string REPORT_CHILD_REZZED = "#reziam";
-    // requests that this class report to the root jaunter that a child has rezzed and
-    // is ready for service.  there are no required parameters.
-string REZOLATOR_CHILD_SUPPORT = "#rzsup";
-    // used by child jaunters to request that the rezolator handle things for them.
-string REZOLATOR_CHILD_RETURNED = "#rezdon";
-    // used by the child jaunter to tell the rezolator that it has jumped to wherever it
-    // was supposed to and is ready to report to the parent, if needed.  the first parameter
-    // required for the rezolator is whether the jump was successful (1) or not (0), and
-    // the second parameter should be the last safe position that the jaunter was at when
-    // it was possibly closest to the target.
-//////////////
-// events generated by the library:
-//string REZOLATOR_EVENT_REZZED_CHILD = "#donekd";
-    // an event generated for a previous rez child request.  this lets the caller know that
-    // the child has been created and told what to do.  the single parameter is where the
-    // jaunter has been rezzed.
-string REZOLATOR_EVENT_GOT_INSTRUCTIONS = "#rzsta";
-    // the root jaunter has given a child instructions on where to go.  this info includes
-    // the name of the destination, the pathway to get there, and the conveyance mode.
-//string REZOLATOR_EVENT_RECON_FINISHED = "#rzcnfn";
-    // an event generated when the recon process has concluded.  this includes parms:
-    // number of good destinations.
-//
-//////////////
-
-// important constants used internally...  these should not be changed willy nilly.
-
-////////////// jaunt base API
-
-// the following constants define how the script should behave (i.e., its conveyance mode).
-// TWO_WAY_TRIP: the script jaunts using the current target vectors to get somewhere
-//   and then takes the same pathway back, but in reverse order.
-// AUTOREZ_JAUNTER: the script rezzes the first regular object in its inventory next to
-//   the root telehub.  that object is loaded with the destination notecard and this script.
-//   the rezzed object can then be used for the next few minutes to jaunt to the selected
-//   destination.  the temporary object will use the ONE_WAY_TRIP mode.
-// ONE_WAY_TRIP: the object containing this script will take the user to a particular
-//   destination, but the object does not survive the trip.  it self-destructs after
-//   reaching the destination.  this mode is used in conjunction with the AUTOREZ_JAUNTER
-//   mode and should generally never be used on its own.
-// RECONNAISSANCE_TRIP: a survey run to test out a particular path to get to a
-//   destination.
-integer TWO_WAY_TRIP = 1;
-integer AUTOREZ_JAUNTER = 2;
-integer ONE_WAY_TRIP = 3;
-integer RECONNAISSANCE_TRIP = 4;
-
-// values used to represent different stages of verification.
-integer VERIFY_UNTESTED = -3;  // don't know destinations tate yet.
-integer VERIFY_SAFE = -4;  // the destination last tested safe.
-integer VERIFY_UNSAFE_SO_FAR = -5;  // this cannot be done with simple jaunt.
-integer VERIFY_UNSAFE_DECIDED = -6;  // this means the destination seems intractable.
-
-integer MAXIMUM_PRIV_CHAN = 90000;
-    // the largest amount we will ever subtract from the tricky parms in order to
-    // tell the sub-jaunter which channel to listen on.
-
-string VECTOR_SEPARATOR = "|";
-    // how we separate components of vectors from each other.
-string DB_SEPARATOR = "``";  // separating items in lists.
-
-////////////// end jaunt base API
-
-integer MAX_DEST_NAME = 24;  // the longest name that we store.
-
-float NORMAL_TIMER_PERIOD = 1.0;  // our normal timer rate.
-
-float POSITION_CHECKING_INTERVAL = 0.11;
-    // how frequently the waiting for arrival state will check where we are.
-
-integer MAXIMUM_SLACKNESS = 108;
-    // how many timer hits we'll allow before reverting to the default state.
-
-integer FREE_MEM_REQUIRED = 3200;
-    // we need at least this much memory before adding new targets.
-
-//////////////
-
-// global variables.
-
-integer startup_parm;  // recorded at rez time.  used for deciding what to do.
-
-integer conveyance_mode;  // when we are given our instructions, we will know what type of jump to use.
-
-// jaunter target configuration...
-string global_name;  // the name for our destination.
-integer global_verification_state;  // the verification state of the last destination we asked for.
-string global_pathway;  // similar, but the last pathway we heard.
-
-// jaunt trip variables...
-vector eventual_destination;  // where we're headed, if we're headed anywhere.
-integer slackness_counter;  // snoozes had while waiting for destination.
-list full_journey;  // the full pathway we expect to jaunt on.
-integer jaunt_responses_awaited;  // number of pending jumps in progress.
-integer got_close_enough;  // did we arrive at right place?
-vector last_safe_position;  // where did we actually reach?
-
-// asks the jaunting library to take us to the target using a list of waypoints.
-request_jaunt(list journey, integer forwards)
-{
-    // ask for a jump.
-    jaunt_responses_awaited++;
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_LIST_COMMAND,
-        wrap_item_list(journey) + HUFFWARE_PARM_SEPARATOR + (string)forwards);
-    // stops the jaunter in its tracks.
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, FULL_STOP_COMMAND, ""); 
-}
-
-// this function returns TRUE if we are close enough to the "destination".
-integer close_enough(vector destination)
-{
-    float PROXIMITY_REQUIRED = 0.1;
-        // how close we must be to the target location to call it done.
-        // matches current jaunting library proximity.
-    return (llVecDist(llGetPos(), destination) <= PROXIMITY_REQUIRED);
-}
-
-// sets up the initial state.
-initialize_child()
-{
-    llSetTimerEvent(0.0);  // cancel any existing timers.
-    // load up an arrival sound if any exist.
-    if (llGetInventoryNumber(INVENTORY_SOUND))
-        llPreloadSound(llGetInventoryName(INVENTORY_SOUND, 0));
-    if (DEBUGGING) log_it("child init startparm=" + (string)startup_parm);
-
-//voodoo.
-    llSleep(0.5);
-    
-    if (startup_parm != 0) {
-        // tell the rezolator to start listening for commands.
-        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZOLATOR_CHILD_SUPPORT,
-            wrap_parameters([startup_parm]));
-        // let our parent know we're here.
-        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REPORT_CHILD_REZZED, "");
-    }
-    // set up some of the object properties...
-    llSetSitText("Jaunt");  // change to the proper text for our mode.
-}
-
-// shows our next target for jaunting above the object.
-text_label_for_destination()
-{
-    string msg = "↣ " + global_name;
-    llSetText(msg, (vector)TEXT_COLOR, 1.0);
-}
-
-// signal that we are where we were going.
-proclaim_arrival()
-{
-    if (conveyance_mode == ONE_WAY_TRIP) {
-        // sing a little song, if there's a sound to use.
-        if (llGetInventoryNumber(INVENTORY_SOUND))
-            llTriggerSound(llGetInventoryName(INVENTORY_SOUND, 0), 1.0);
-    }
-}
-
-string verification_name(integer enumtype)
-{
-    if (enumtype == VERIFY_SAFE) return "ok";
-    else if (enumtype == VERIFY_UNSAFE_SO_FAR) return "uhh";
-    else if (enumtype == VERIFY_UNSAFE_DECIDED) return "far";
-    // catch-all, including untested.
-    return "?";
-}
-
-// returns true if the slackness counter awaiting things has elapsed.
-integer check_for_timeout()
-{
-    if (slackness_counter++ > MAXIMUM_SLACKNESS) {
-        // go back to the main state.  we took too long.
-        log_it("timed out!");
-        llUnSit(llAvatarOnSitTarget());  // don't hang onto the avatar for this error.
-        llSetTimerEvent(0.0);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-//////////////
-
-// returns the value of a boolean variable definition.
-integer parse_bool_def(string def)
-{ return !(llGetSubString(def, find_substring(def, "=") + 1, -1) == "0"); }
-
-// processes link messages received from support libraries.
-integer handle_link_message(integer which, integer num, string msg, string id)
-{
-    // is it a jaunting library response?
-    if (num == JAUNT_HUFFWARE_ID + REPLY_DISTANCE) {
-        jaunt_responses_awaited--;  // one less response being awaited.
-        if (jaunt_responses_awaited < 0) {
-            log_it("error: responses awaited < 0");
-            jaunt_responses_awaited = 0;
-        }
-        return FALSE;
-    }
-    
-    // is it an event from the rezolator script?
-    if (num == JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        if (msg == REZOLATOR_EVENT_GOT_INSTRUCTIONS) {
-            global_name = llList2String(parms, 0);
-            full_journey = [ llGetPos() ] + llParseString2List(llList2String(parms, 1), [VECTOR_SEPARATOR], []);
-            eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
-            conveyance_mode = llList2Integer(parms, 2);
-            if (DEBUGGING)
-                log_it("got instructions: name=" + global_name + " dest=" + (string)eventual_destination);
-            text_label_for_destination();
-            if (conveyance_mode == RECONNAISSANCE_TRIP) {
-                return TRUE;
-            }
-        }
-        return FALSE;
-    }
-
-    return FALSE;
-}
-
-// processes a destination set to handle special cases, like for offset jaunting.
-list prechewed_destinations(string dests)
-{
-
-//document this!!!
-// as in, we support the offset format!
-
-    // look for our special start character for offsets.
-    if (is_prefix(dests, "o"))
-        // if this is an offset version, then chop whatever word they used starting with 'o'
-        // and compute the destination based on current position.
-        return [ (vector)llDeleteSubString(dests, 0, find_substring(dests, "<") - 1) + llGetPos() ];
-    else
-        // normal jaunt to absolute coordinates.
-        return llParseString2List(dests, [VECTOR_SEPARATOR], []);
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-///////////////
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-// returns TRUE if the "to_check" vector is a location outside of the current sim.
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-// returns text for a floating point number, but includes only
-// two digits after the decimal point.
-string float_chop(float to_show)
-{
-    integer mant = llAbs(llRound(to_show * 100.0) / 100);
-    string neg_sign;
-    if (to_show < 0.0) neg_sign = "-";
-    string dec_s = (string)((llRound(to_show * 100.0) - mant * 100) / 100.0);
-    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
-    // strip off all trailing zeros.
-    while (llGetSubString(dec_s, -1, -1) == "0")
-        dec_s = llDeleteSubString(dec_s, -1, -1);
-    string to_return = neg_sign + (string)mant;
-    if (llStringLength(dec_s)) to_return += "." + dec_s;
-    return to_return;
-}
-
-// returns a prettier form for vector text, with chopped floats.
-string vector_chop(vector to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ">";
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{
-    string full_lower = llToLower(full_string);
-    return llSubStringIndex(full_lower, pattern);
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//////////////
-
-// default state scrounges for information in a notecard and looks for landmarks in
-// inventory to add as destinations.
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) {
-        startup_parm = parm; 
-        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
-        state rerun;
-    }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        if (DEBUGGING) log_it("=> real_default state, mem=" + (string)llGetFreeMemory());
-        initialize_child();
-        state normal_runtime;
-    }
-    
-    on_rez(integer parm) {
-        startup_parm = parm; 
-        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
-        state default;
-    }
-}
-
-// the normal state is pretty calm; the jaunter just sits there waiting for
-// an avatar who needs it to do something.
-state normal_runtime
-{
-    state_entry() {
-        if (DEBUGGING) log_it("=> normal state, mem=" + (string)llGetFreeMemory());
-        jaunt_responses_awaited = 0;  // nothing pending right now.
-        got_close_enough = FALSE;  // have not even tried going there yet.
-    }
-
-    on_rez(integer parm) {
-        startup_parm = parm;
-        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
-        state default;
-    }
-
-    touch_end(integer total_number) {
-        // if we got to here, we may need to check the safety of the target and show the
-        // map if the conditions are right.
-        if (outside_of_sim(eventual_destination)) {
-            // bring up the map; maybe we can't get there from here.  definitely out of sim.
-            llMapDestination(llGetRegionName(), eventual_destination, ZERO_VECTOR);
-            proclaim_arrival();
-        }
-    }
-
-    changed(integer change) {
-        if (!(change & CHANGED_LINK)) return;  // don't care then.
-//no, bad, ack.  if the jaunter has multiple parts and they sit on non-root prim, this breaks our ability to react to sit events properly.        if (llAvatarOnSitTarget() == NULL_KEY) return;  // there is no one sitting now.
-        if (outside_of_sim(eventual_destination)) {
-            llWhisper(0, "This type of jaunter needs to be clicked rather than sat upon.  Please left-click it (or right-click it and select 'touch').");
-            llUnSit(llAvatarOnSitTarget());
-            return;
-        }
-        state jaunting_now;  // sweet, we're off.
-    }
-
-    // process the response from the APIs we use.
-    link_message(integer which, integer num, string msg, key id) {
-        if (handle_link_message(which, num, msg, id)) state jaunting_now;
-    }
-    
-}
-
-// once someone is trying to jump to a target, this state processes the request.
-state jaunting_now
-{
-    state_entry() {
-        if (DEBUGGING) log_it("=> jauntnow state, posn=" + vector_chop(llGetPos()));
-        slackness_counter = 0;
-        // most jaunters go to at least the first location...
-        request_jaunt(full_journey, TRUE);
-        eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
-        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-    }
-
-    on_rez(integer parm)
-    {
-        startup_parm = parm;
-        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
-        state default;
-    }
-
-    timer() {
-        if (jaunt_responses_awaited) {
-            // we are not quite there yet.
-            if (check_for_timeout()) state normal_runtime;  // oops.
-            return;  // not time yet.
-        }
-        // we got to where we were going, maybe.  unseat the avatar, leaving her
-        // at the destination.
-        llUnSit(llAvatarOnSitTarget());
-        state arrived_at_target;
-    }
-
-    // process the response from the jaunting library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-}
-
-// this state is activated when the first jaunt is complete.
-state arrived_at_target
-{
-    state_entry() {
-        if (DEBUGGING) log_it("=> arriv targ state, posn=" + vector_chop(llGetPos()));
-        // we are close enough; get back to work.
-        jaunt_responses_awaited = 0;  // nothing pending right now.
-        if (conveyance_mode != RECONNAISSANCE_TRIP) {
-            llWhisper(0, "↣ " + global_name);
-        } else {
-            if (DEBUGGING) {
-                string close = "yep";
-                if (!close_enough(eventual_destination)) close = "nope";
-                log_it("close enough here? " + close + ", want to get to "
-                    + (string)eventual_destination);
-            }
-            got_close_enough = close_enough(eventual_destination);
-            last_safe_position = llGetPos();
-        }
-
-        // we've gotten where we were going.
-        proclaim_arrival();
-
-//hmmm: nice mod to make the one way trip actually flip its target list and allow a return.
-
-        // reverse direction and head back without rider.
-        eventual_destination = (vector)llList2String(full_journey, 0);
-        request_jaunt(full_journey, FALSE);
-        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-        slackness_counter = 0;
-        if (DEBUGGING) log_it("now trying to jaunt home, responses awaited=" + (string)jaunt_responses_awaited);
-    }
-
-    on_rez(integer parm) {
-        startup_parm = parm; 
-        if (DEBUGGING) log_it("default onrez " + (string)startup_parm);
-        state default;
-    }
-
-    timer() {
-        if (jaunt_responses_awaited) {
-            // we are not quite there yet.
-            if (check_for_timeout()) state normal_runtime;  // oops.
-            return;  // not time yet.
-        }
-        if (DEBUGGING) log_it("==> telling parent we got back, now at posn: " + (string)llGetPos());
-        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZOLATOR_CHILD_RETURNED,
-            wrap_parameters([got_close_enough, 
-                llDumpList2String(llDeleteSubList(full_journey, 0, 0) + [ last_safe_position ],
-                    VECTOR_SEPARATOR)]));
-        state normal_runtime;
-    }
-    
-    // process the response from the jaunting library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); } 
-}
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/coastal_connector_hubs_v2.4.lsl b/huffware/huffotronic_jaunter_updater_v5.1/coastal_connector_hubs_v2.4.lsl
new file mode 100755 (executable)
index 0000000..2382a84
--- /dev/null
@@ -0,0 +1,12 @@
+#jaunt
+:add_name=1
+<30, 105, 1825>
+huffhines landing
+<14, 74, 41>
+ground floor
+<48, 105, 95>
+perilous walkways v4
+<46, 97, 38>
+coastal connector
+<14, 84, 405>
+eepaw shop
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/coastal_connector_hubs_v2.4.txt b/huffware/huffotronic_jaunter_updater_v5.1/coastal_connector_hubs_v2.4.txt
deleted file mode 100755 (executable)
index 2382a84..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#jaunt
-:add_name=1
-<30, 105, 1825>
-huffhines landing
-<14, 74, 41>
-ground floor
-<48, 105, 95>
-perilous walkways v4
-<46, 97, 38>
-coastal connector
-<14, 84, 405>
-eepaw shop
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/data_cow_v3.3.lsl b/huffware/huffotronic_jaunter_updater_v5.1/data_cow_v3.3.lsl
new file mode 100755 (executable)
index 0000000..c03cb4c
--- /dev/null
@@ -0,0 +1,227 @@
+
+// huffware script: data cow, by fred huffhines.
+//
+// a data cow is a script that manages a list of text items.  it allows an object
+// to offload the memory burden of managing a list of items, since LSL is very tight
+// on memory, even when compiled to mono.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global variables.
+
+list the_list;
+    // the main list that we manage here.  we support adding to it, retrieving it
+    // and modifying it via our API.
+list the_names;
+    // the short names for each item in our list.  we are basically supporting a
+    // symbol table data structure here.
+
+// link message API for the data cow library.
+//////////////
+// do not redefine these constants.
+integer DATA_COW_HUFFWARE_ID = 10017;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+///string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+//
+string RESET_LIST_COMMAND = "reset_L";
+    // flushes out the currently held list.  does not send a reply.
+string ADD_ITEM_COMMAND = "add_I";
+    // adds items to the list.  this is a list of pairs of name/value, where the name is
+    // how the item will be looked up from the list, and the value is the contents to be stored.
+    // this command has no reply.
+string REMOVE_ITEM_COMMAND = "rm_I";
+    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
+    // this command also has no reply.
+string GET_COW_LENGTH = "get_Lc";
+    // returns a single integer which is the length of the cow's list currently.
+string GET_ITEM_COMMAND = "get_I";
+    // retrieves the item's contents for a given name.  first parm is the name.  if there
+    // are other parameters, then they are taken as other items to return also.
+    // the return data will be pairs of <name, entry> for each of the names in the request
+    // that is not empty.  note that you can use an integer index by prefacing it with a
+    // '#' sign.  for example, asking for item "#32" will return index 32 in the list of items.
+string TAGGED_GET_ITEM_COMMAND = "get_T";
+    // like get item, except the first parameter is an identifier that the caller wants to
+    // use to tag this request.  the other parameters are still taken as names.  the response
+    // will contain the tag as the first item, then the <name, entry> pairs that were found.
+//////////////
+
+// sets up the data cow for business.
+initialize()
+{
+    // flush all contents.
+    the_list = [];
+    the_names = [];
+}
+
+// find a named item in our list, if it exists.
+integer lookup_item(string name)
+{
+    integer indy;
+    if (llGetSubString(name, 0, 0) == "#") {
+        // our special sign for just using an index.
+        indy = (integer)llGetSubString(name, 1, -1);
+        if ( (indy >= 0) && (indy < llGetListLength(the_names)) ) return indy;
+    } else {
+        for (indy = 0; indy < llGetListLength(the_names); indy++) {
+            if (name == llList2String(the_names, indy)) return indy;  // we know where it is now.
+        }
+    }
+    return -1;  // never found it.
+}
+
+// places a named item in our list.  if there's an existing item with
+// that name, then it's replaced.
+integer global_mem_complained = FALSE;
+add_item(string name, string content)
+{
+    if (llGetFreeMemory() < 2000) {
+        if (!global_mem_complained) {
+            global_mem_complained = TRUE;
+            llOwnerSay("out of memory at " + name);
+        }
+        return;
+    }
+    integer current = lookup_item(name);
+    if (current < 0) {
+//llOwnerSay("new item: " + name);
+        // this is a new item.
+        the_names += name;
+        the_list += content;
+    } else {
+//llOwnerSay("reusing slot " + (string)current + " for " + name);
+        // this is an old item to be replaced.
+        the_list = chop_list(the_list, 0, current - 1)
+            + [ content ]
+            + chop_list(the_list, current + 1, llGetListLength(the_list) - 1);
+    }
+//log_it("mem=" + (string)llGetFreeMemory());
+}
+
+// deletes an existing item if possible.  TRUE is returned on success.
+integer remove_item(string name)
+{
+    integer indy = lookup_item(name);
+    if (indy < 0) return FALSE;  // not present.
+    // found our sad whackee.  we know the name and content should be
+    // stored at the exact same index in the two lists.
+    the_names = chop_list(the_names, 0, indy - 1)
+        + chop_list(the_names, indy + 1, llGetListLength(the_names) - 1);
+    the_list = chop_list(the_list, 0, indy - 1)
+        + chop_list(the_list, indy + 1, llGetListLength(the_list) - 1);
+    return TRUE;  // all done here.
+}
+
+// supports our link message API by answering requests from clients.
+handle_link_message(integer sender, integer num, string msg, key id)
+{
+    if (num != DATA_COW_HUFFWARE_ID) return;  // not for us.
+//log_it("hlm--mem free=" + (string)llGetFreeMemory());
+//log_it("rcvd: " + msg + " " + (string)num + " " + (string)id);
+    if (msg == RESET_LIST_COMMAND) {
+        initialize();
+    } else if (msg == ADD_ITEM_COMMAND) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        integer indy;
+        for (indy = 0; indy < llGetListLength(parms); indy += 2) {
+            add_item(llList2String(parms, indy), llList2String(parms, indy + 1));
+        }
+    } else if (msg == REMOVE_ITEM_COMMAND) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        integer indy;
+        for (indy = 0; indy < llGetListLength(parms); indy++) {
+            remove_item(llList2String(parms, indy));
+        }
+    } else if (msg == GET_COW_LENGTH) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        string tag = llList2String(parms, 0);
+        list to_reply;
+        if (tag != "") to_reply = [ tag ];
+        to_reply += [ llGetListLength(the_list) ];
+        send_reply(LINK_THIS, to_reply, msg);
+    } else if ( (msg == GET_ITEM_COMMAND) || (msg == TAGGED_GET_ITEM_COMMAND) ) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        integer indy;
+        string tag;
+        if (msg == TAGGED_GET_ITEM_COMMAND) {
+            // extract the tag, if they want that type of command handling.
+            tag = llList2String(parms, 0);
+            parms = llDeleteSubList(parms, 0, 0);
+        }
+        list to_reply;
+        // make sure we return the tag if they gave us one.
+        if (tag != "") to_reply = [ tag ];
+        for (indy = 0; indy < llGetListLength(parms); indy++) {
+            // iterate through the parameters and reply about any that we find.
+            integer found_posn = lookup_item(llList2String(parms, indy));
+            if (found_posn >= 0) {
+                // this item did exist.
+                to_reply += [ llList2String(the_names, found_posn), llList2String(the_list, found_posn) ];
+            }
+        }
+        send_reply(LINK_THIS, to_reply, msg);
+    } 
+}
+
+//////////////
+// from hufflets...
+//
+//integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+//log_it(string to_say)
+//{
+//    debug_num++;
+//    // tell this to the owner.    
+//    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//    // say this on open chat, but use an unusual channel.
+////    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply(integer destination, list parms, string command)
+{
+    llMessageLinked(destination, DATA_COW_HUFFWARE_ID + REPLY_DISTANCE,
+        command,  llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+//
+// end hufflets
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { initialize(); }
+
+    link_message(integer sender, integer num, string msg, key id)
+    { handle_link_message(sender, num, msg, id); }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/data_cow_v3.3.txt b/huffware/huffotronic_jaunter_updater_v5.1/data_cow_v3.3.txt
deleted file mode 100755 (executable)
index c03cb4c..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-
-// huffware script: data cow, by fred huffhines.
-//
-// a data cow is a script that manages a list of text items.  it allows an object
-// to offload the memory burden of managing a list of items, since LSL is very tight
-// on memory, even when compiled to mono.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global variables.
-
-list the_list;
-    // the main list that we manage here.  we support adding to it, retrieving it
-    // and modifying it via our API.
-list the_names;
-    // the short names for each item in our list.  we are basically supporting a
-    // symbol table data structure here.
-
-// link message API for the data cow library.
-//////////////
-// do not redefine these constants.
-integer DATA_COW_HUFFWARE_ID = 10017;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-///string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-//
-string RESET_LIST_COMMAND = "reset_L";
-    // flushes out the currently held list.  does not send a reply.
-string ADD_ITEM_COMMAND = "add_I";
-    // adds items to the list.  this is a list of pairs of name/value, where the name is
-    // how the item will be looked up from the list, and the value is the contents to be stored.
-    // this command has no reply.
-string REMOVE_ITEM_COMMAND = "rm_I";
-    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
-    // this command also has no reply.
-string GET_COW_LENGTH = "get_Lc";
-    // returns a single integer which is the length of the cow's list currently.
-string GET_ITEM_COMMAND = "get_I";
-    // retrieves the item's contents for a given name.  first parm is the name.  if there
-    // are other parameters, then they are taken as other items to return also.
-    // the return data will be pairs of <name, entry> for each of the names in the request
-    // that is not empty.  note that you can use an integer index by prefacing it with a
-    // '#' sign.  for example, asking for item "#32" will return index 32 in the list of items.
-string TAGGED_GET_ITEM_COMMAND = "get_T";
-    // like get item, except the first parameter is an identifier that the caller wants to
-    // use to tag this request.  the other parameters are still taken as names.  the response
-    // will contain the tag as the first item, then the <name, entry> pairs that were found.
-//////////////
-
-// sets up the data cow for business.
-initialize()
-{
-    // flush all contents.
-    the_list = [];
-    the_names = [];
-}
-
-// find a named item in our list, if it exists.
-integer lookup_item(string name)
-{
-    integer indy;
-    if (llGetSubString(name, 0, 0) == "#") {
-        // our special sign for just using an index.
-        indy = (integer)llGetSubString(name, 1, -1);
-        if ( (indy >= 0) && (indy < llGetListLength(the_names)) ) return indy;
-    } else {
-        for (indy = 0; indy < llGetListLength(the_names); indy++) {
-            if (name == llList2String(the_names, indy)) return indy;  // we know where it is now.
-        }
-    }
-    return -1;  // never found it.
-}
-
-// places a named item in our list.  if there's an existing item with
-// that name, then it's replaced.
-integer global_mem_complained = FALSE;
-add_item(string name, string content)
-{
-    if (llGetFreeMemory() < 2000) {
-        if (!global_mem_complained) {
-            global_mem_complained = TRUE;
-            llOwnerSay("out of memory at " + name);
-        }
-        return;
-    }
-    integer current = lookup_item(name);
-    if (current < 0) {
-//llOwnerSay("new item: " + name);
-        // this is a new item.
-        the_names += name;
-        the_list += content;
-    } else {
-//llOwnerSay("reusing slot " + (string)current + " for " + name);
-        // this is an old item to be replaced.
-        the_list = chop_list(the_list, 0, current - 1)
-            + [ content ]
-            + chop_list(the_list, current + 1, llGetListLength(the_list) - 1);
-    }
-//log_it("mem=" + (string)llGetFreeMemory());
-}
-
-// deletes an existing item if possible.  TRUE is returned on success.
-integer remove_item(string name)
-{
-    integer indy = lookup_item(name);
-    if (indy < 0) return FALSE;  // not present.
-    // found our sad whackee.  we know the name and content should be
-    // stored at the exact same index in the two lists.
-    the_names = chop_list(the_names, 0, indy - 1)
-        + chop_list(the_names, indy + 1, llGetListLength(the_names) - 1);
-    the_list = chop_list(the_list, 0, indy - 1)
-        + chop_list(the_list, indy + 1, llGetListLength(the_list) - 1);
-    return TRUE;  // all done here.
-}
-
-// supports our link message API by answering requests from clients.
-handle_link_message(integer sender, integer num, string msg, key id)
-{
-    if (num != DATA_COW_HUFFWARE_ID) return;  // not for us.
-//log_it("hlm--mem free=" + (string)llGetFreeMemory());
-//log_it("rcvd: " + msg + " " + (string)num + " " + (string)id);
-    if (msg == RESET_LIST_COMMAND) {
-        initialize();
-    } else if (msg == ADD_ITEM_COMMAND) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        integer indy;
-        for (indy = 0; indy < llGetListLength(parms); indy += 2) {
-            add_item(llList2String(parms, indy), llList2String(parms, indy + 1));
-        }
-    } else if (msg == REMOVE_ITEM_COMMAND) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        integer indy;
-        for (indy = 0; indy < llGetListLength(parms); indy++) {
-            remove_item(llList2String(parms, indy));
-        }
-    } else if (msg == GET_COW_LENGTH) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        string tag = llList2String(parms, 0);
-        list to_reply;
-        if (tag != "") to_reply = [ tag ];
-        to_reply += [ llGetListLength(the_list) ];
-        send_reply(LINK_THIS, to_reply, msg);
-    } else if ( (msg == GET_ITEM_COMMAND) || (msg == TAGGED_GET_ITEM_COMMAND) ) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        integer indy;
-        string tag;
-        if (msg == TAGGED_GET_ITEM_COMMAND) {
-            // extract the tag, if they want that type of command handling.
-            tag = llList2String(parms, 0);
-            parms = llDeleteSubList(parms, 0, 0);
-        }
-        list to_reply;
-        // make sure we return the tag if they gave us one.
-        if (tag != "") to_reply = [ tag ];
-        for (indy = 0; indy < llGetListLength(parms); indy++) {
-            // iterate through the parameters and reply about any that we find.
-            integer found_posn = lookup_item(llList2String(parms, indy));
-            if (found_posn >= 0) {
-                // this item did exist.
-                to_reply += [ llList2String(the_names, found_posn), llList2String(the_list, found_posn) ];
-            }
-        }
-        send_reply(LINK_THIS, to_reply, msg);
-    } 
-}
-
-//////////////
-// from hufflets...
-//
-//integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-//log_it(string to_say)
-//{
-//    debug_num++;
-//    // tell this to the owner.    
-//    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//    // say this on open chat, but use an unusual channel.
-////    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply(integer destination, list parms, string command)
-{
-    llMessageLinked(destination, DATA_COW_HUFFWARE_ID + REPLY_DISTANCE,
-        command,  llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-//
-// end hufflets
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { initialize(); }
-
-    link_message(integer sender, integer num, string msg, key id)
-    { handle_link_message(sender, num, msg, id); }
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/fred_main_hubs_v5.4.lsl b/huffware/huffotronic_jaunter_updater_v5.1/fred_main_hubs_v5.4.lsl
new file mode 100755 (executable)
index 0000000..9745878
--- /dev/null
@@ -0,0 +1,25 @@
+#jaunt
+:show_text=1
+:add_name=1
+<14, 74, 41>
+ground floor
+<46, 97, 38>
+coastal connector
+<47, 105, 85>
+worm tube walkway
+<11, 75, 99>
+penthouse de moo
+<17, 76, 109>
+flower deck
+<48, 105, 95>
+perilous walkways v4
+<42, 86, 750>
+high sierra testing zone
+<34, 90, 1008>
+om 1008 disc
+<24, 72, 1224>
+get ready--long drop
+<36, 93, 4095>
+nearly off world
+<14, 84, 405>
+eepaw shop
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/fred_main_hubs_v5.4.txt b/huffware/huffotronic_jaunter_updater_v5.1/fred_main_hubs_v5.4.txt
deleted file mode 100755 (executable)
index 9745878..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#jaunt
-:show_text=1
-:add_name=1
-<14, 74, 41>
-ground floor
-<46, 97, 38>
-coastal connector
-<47, 105, 85>
-worm tube walkway
-<11, 75, 99>
-penthouse de moo
-<17, 76, 109>
-flower deck
-<48, 105, 95>
-perilous walkways v4
-<42, 86, 750>
-high sierra testing zone
-<34, 90, 1008>
-om 1008 disc
-<24, 72, 1224>
-get ready--long drop
-<36, 93, 4095>
-nearly off world
-<14, 84, 405>
-eepaw shop
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/huff-update_client_v20.1.lsl b/huffware/huffotronic_jaunter_updater_v5.1/huff-update_client_v20.1.lsl
new file mode 100755 (executable)
index 0000000..4a458bb
--- /dev/null
@@ -0,0 +1,826 @@
+
+// huffware script: huff-update client, by fred huffhines.
+//
+// this script is the client side of the update process.  it should reside in an object that
+// has scripts which should be automatically updated.  it will listen for announcements by
+// an update server and communicate with the server to ensure that all of its scripts are
+// the most up to date available with the server.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+integer DEBUGGING = FALSE;  // if TRUE, the script will output status information.
+
+integer SERVER_IGNORE_TIME = 1200;  // number of seconds between performing an upgrade with the same server.
+
+integer MAXIMUM_UPDATE_TIME_ALLOWED = 140;  // we allow one upgrade process to take this long overall.
+
+integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
+integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
+
+string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
+string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
+string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
+string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
+string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
+string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
+string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
+string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
+string DONE_UPDATING                = "#finito#";  // the client is done updating.
+string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
+
+float UPDATE_TIMER_INTERVAL = 2.0;  // interval between checks on our update status.
+
+integer UPDATER_SCRIPT_PIN = -1231008;  // the hook for our scripts to be modified.
+
+///float BUSY_SERVER_PAUSE_TIME = 38.0;  // num seconds to delay when server says it's too busy.
+
+string UPDATER_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+
+string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
+string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
+
+integer MAXIMUM_SERVERS_TRACKED = 32;
+    // we will listen to this many servers before we decide to remove one.
+
+string CONTINUANCE_MARKER = "...";
+    // a string sent when the update list is too long and needs to be continued in another chat.
+
+string SERVER_SCRIPT = "a huffotronic update server";
+    // the prefix of our server script that hands out updates.
+
+// global variables...
+
+integer inventory_request_channel;  // used for newer version servers to cut down cross chatter.
+list updaters_heard;  // the update servers we've heard from recently.
+list last_interactions;  // times of the last update process engaged with the updater.
+integer update_channel;  // current channel for interaction with specific server.
+key current_server;  // the updater that is active right now, if any.
+integer update_start_time;  // when the last update process began.
+list updates_needed;  // stores the set of scripts that are in need of an update.
+list known_script_dependencies;  // stores the list of dependency info.
+
+careful_crankup()
+{
+    knock_around_other_scripts(TRUE);
+    // clean out the older items and scripts.  we do this after getting everyone running
+    // since we might be whacking ourselves.
+    destroy_older_versions();
+}
+
+// reset our variables.
+initialize()
+{
+    updaters_heard = [];
+    last_interactions = [];
+    inventory_request_channel = 0;
+    update_channel = 0;
+    current_server = NULL_KEY;
+    llSetTimerEvent(0.0);
+    llSetRemoteScriptAccessPin(UPDATER_SCRIPT_PIN);
+    // a new enhancements; tells the server that this guy has finished an update cycle.  this
+    // only comes into play when the updater script itself has just been updated, but it's
+    // nice for the server to avoid claiming erroneous timeouts occurred.
+    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
+    llSleep(0.4);  // snooze and repeat to overcome occasionally lossy chats.
+    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
+}
+
+whack_updater_record(key id)
+{
+    integer prev_indy = find_in_list(updaters_heard, id);
+    if (prev_indy < 0) return;  // not there.
+    updaters_heard = chop_list(updaters_heard, 0, prev_indy - 1)
+            + chop_list(updaters_heard, prev_indy + 1, llGetListLength(updaters_heard) - 1);
+    last_interactions = chop_list(last_interactions, 0, prev_indy - 1)
+            + chop_list(last_interactions, prev_indy + 1, llGetListLength(last_interactions) - 1);
+}
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        if (DEBUGGING)
+            log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+    // thirdly, try to clean out the notecards.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
+}
+
+// sets the object to be listening for update info.
+// if "just_owner" is true, then we will not listen on the general announcement channel.
+listen_for_orders(integer just_owner)
+{
+    if (!just_owner) {
+        // try to hear an update being announced.
+        llListen(UPDATE_ANNOUNCEMENT_CHANNEL, "", NULL_KEY, "");
+    }
+
+    // super secret owner controls.
+    llListen(0, "", llGetOwner(), "");
+}
+
+// returns true if this object is a huffotronic updater of some sort.
+integer inside_of_updater()
+{
+    return find_substring(llGetObjectName(), "huffotronic") >= 0;
+}
+
+// returns true if a script is a version of our update server.
+integer matches_server_script(string to_check)
+{
+    return is_prefix(to_check, SERVER_SCRIPT);
+}
+
+// stops all the scripts besides this one.
+knock_around_other_scripts(integer running_state)
+{
+    integer insider = inside_of_updater();
+    if (running_state == TRUE) {
+        // make sure we crank up the scripts that are new first.  we want to reset them
+        // as well, which we don't want to do for any existing scripts.
+        integer crank_indy;
+        for (crank_indy = 0; crank_indy < llGetListLength(updates_needed); crank_indy++) {
+            string crankee = llList2String(updates_needed, crank_indy);
+            if (find_in_inventory(crankee, INVENTORY_SCRIPT, TRUE) >= 0) {
+                if (!insider || matches_server_script(crankee)) {
+                    // allow it to run again.
+                    llSetScriptState(crankee, TRUE);
+                    // reset it, to make sure it starts at the top.
+                    llResetOtherScript(crankee);
+                }
+            }
+        }
+    }
+
+    integer indy;
+    string self_script = llGetScriptName();
+    // we set all other scripts to the running state requested.
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if ( (curr_script != self_script)
+            && (!insider || matches_server_script(curr_script)) ) {
+            // this one seems ripe for being set to the state requested.
+            llSetScriptState(curr_script, running_state);
+        }
+    }
+}
+
+// a random channel for the interaction with the server.
+integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
+
+// make sure that any dependencies for the script with "basename" are added to the list
+// of requests we make during an update.
+list add_dependencies(string basename)
+{
+    list to_return;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(known_script_dependencies); indy++) {
+        list deps = llParseString2List(llList2String(known_script_dependencies, indy),
+            [ITEM_LIST_SEPARATOR], []);
+//log_it("base=" + llList2String(dep, 0) + " lastver=" + llList2String(dep, 1) + " newdep=" + llList2String(dep, 2));
+        if (basename == llList2String(deps, 0)) {
+            // first off, is this item with new dependencies actually present?
+            integer where = find_in_inventory(basename, INVENTORY_SCRIPT, FALSE);
+            if (where >= 0) {
+                // we do use the script with deps, but is the dependent item really missing?
+                where = find_in_inventory(llList2String(deps, 1), INVENTORY_SCRIPT, FALSE);
+                if (where < 0) {
+                    // we found a dependency match for this script, so we'll ask for the missing item.
+                    if (DEBUGGING)
+                        log_it("missing dep: " + llList2String(deps, 1));
+                    to_return += [ llList2String(deps, 1) ];
+                }
+            }
+        }
+    }
+    return to_return;
+}
+
+// complains if memory seems to be getting tight.
+test_memory()
+{
+    if (llGetFreeMemory() < 4096)
+        log_it("mem_free = " + (string)llGetFreeMemory());
+}
+
+// starts an update given a list of scripts that the server has available, encoded as
+// a string in the "encoded_list".
+integer initiate_update(string encoded_list)
+{
+    list scripts_avail = llParseString2List(encoded_list, [UPDATER_PARM_SEPARATOR], []);
+    integer continue_listening_for_scripts = FALSE;
+      // if true, we aren't done hearing about available scripts yet.
+    encoded_list = "";
+    // figure out which scripts we need by comparing the list available from the server
+    // against our current inventory.  we only want scripts with newer version numbers.
+    integer sindy;
+    for (sindy = 0; sindy < llGetListLength(scripts_avail); sindy++) {
+        string curr = llList2String(scripts_avail, sindy);
+        if (curr == CONTINUANCE_MARKER) {
+            // this is a special continuation signal.  we need to hear the rest of the list.
+            continue_listening_for_scripts = TRUE;
+        } else if (is_prefix(curr, SCRIPT_DEPENDENCY_MARK)) {
+            // we've found a dependency item.
+            known_script_dependencies += [ llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1) ];
+//log_it("script dep: " + llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1));
+        } else {
+            list split = compute_basename_and_version(curr);
+            if (llGetListLength(split) == 2) {
+                string basename = llList2String(split, 0);
+                string version = llList2String(split, 1);
+                split = [];
+                integer oy_indy;
+//replace common code with func.
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_OBJECT); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_OBJECT, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+//                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+//                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_NOTECARD); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_NOTECARD, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_SCRIPT); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_SCRIPT, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                updates_needed += add_dependencies(basename);
+            }
+        }
+    }
+    // we skip the next step if we're still waiting to hear about more.
+    if (continue_listening_for_scripts) {
+//log_it("still listening for more updates...");
+        return FALSE;
+    }
+    if (llGetListLength(updates_needed)) {
+//log_it("update chan=" + (string)update_channel);
+        llSay(update_channel, REQUEST_SCRIPT_UPDATE);
+        if (DEBUGGING) {
+            log_it("told server " + (string)inventory_request_channel + " that i need updating.");
+        }
+    } else {
+        if (DEBUGGING) {
+            log_it("told server " + (string)inventory_request_channel + " that i am done updating.");
+        }
+        llSay(update_channel, DONE_UPDATING);
+    }
+    return TRUE;
+}    
+
+// this alerts the server to our most desired scripts.
+tell_server_our_wish_list()
+{
+    llSay(update_channel, READY_TO_UPDATE + wrap_parameters(updates_needed));
+}
+
+// checks whether all of the updates needed are present yet.
+integer check_on_update_presence()
+{
+    integer indy;
+    for (indy = 0; indy < llGetListLength(updates_needed); indy++) {
+        integer found = find_in_inventory(llList2String(updates_needed, indy), INVENTORY_ALL, TRUE);
+        // any single missing guy means they aren't up to date yet.
+        if (found < 0) {
+            if (DEBUGGING) log_it(llList2String(updates_needed, indy) + " not seen as updated yet.");
+            return FALSE;
+        }
+    }
+    // nothing was detected as missing anymore.
+    return TRUE;
+}
+
+// respond to spoken commands from the server.
+integer process_update_news(integer channel, string name, key id, string message)
+{
+    if (!channel) {
+        // this is a command.
+        if (message == "ureset") {
+            llResetScript();  // start over.
+        }
+        if (message == "ushow") {
+            integer sindy;
+            integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
+            list script_list = [ "scripts--" ];  // first item is just a header.
+            for (sindy = 0; sindy < script_count; sindy++) {
+                script_list += [ llGetInventoryName(INVENTORY_SCRIPT, sindy) ];
+            }
+            dump_list_to_log(script_list);
+        }
+        return FALSE;  // nothing to do here.
+    }
+    if (!update_channel && (channel == UPDATE_ANNOUNCEMENT_CHANNEL)) {
+/* never seen.        if (id == llGetKey()) {
+if (DEBUGGING) log_it("ignoring update from self.");            
+            return FALSE;  // ack, that's our very object.
+        }
+*/
+        if (llStringLength(message) > llStringLength(UPDATE_ANNOUNCEMENT_PREFIX)) {
+            // this is a new style update message.  we can set a different request channel.
+            string just_chan = llDeleteSubString(message, 0, llStringLength(UPDATE_ANNOUNCEMENT_PREFIX) - 1);
+            inventory_request_channel = (integer)just_chan;
+        }
+        integer prev_indy = find_in_list(updaters_heard, id);
+        // find the talker in our list.
+        if (prev_indy >= 0) {
+            // that guy was already heard from.  check when last interacted.
+            integer last_heard = llList2Integer(last_interactions, prev_indy);
+            if (llAbs(llGetUnixTime() - last_heard) < SERVER_IGNORE_TIME) {
+                return FALSE;  // not time to update with this guy again yet.
+            }
+//            if (DEBUGGING) { log_it("started listening again to server " + (string)id); }
+            // make sure we think of this as a new updater now.
+            whack_updater_record(id);
+        }
+
+        if (DEBUGGING) { log_it("heard server " + (string)inventory_request_channel + "'s announcement."); }
+        // record our new server.
+        current_server = id;
+        // make a random pause so not all updaters try to crank up at same time.
+        llSleep(randomize_within_range(2.8, 18.2, FALSE));
+
+        if (llGetListLength(updaters_heard) > MAXIMUM_SERVERS_TRACKED) {
+            // oops, this is not good.  we have too many servers now.
+//hmmm: room for improvement here by tossing out the server that is oldest.
+            updaters_heard = llDeleteSubList(updaters_heard, 0, 0);
+            last_interactions = llDeleteSubList(last_interactions, 0, 0);
+        }
+        
+        // add the talker to our list.
+        updaters_heard += id;
+        last_interactions += llGetUnixTime();
+    
+        // begin the update interaction with this guy.
+        update_channel = random_channel();
+        return TRUE;
+    }
+    if (update_channel && (channel == update_channel) ) {
+        if (is_prefix(message, REPORT_AVAILABLE_SCRIPTS)) {
+            // tasty, this is a list of scripts that can be had.
+            message = llDeleteSubString(message, 0, llStringLength(REPORT_AVAILABLE_SCRIPTS) - 1);
+            if (message == BUSY_BUSY) {
+                // server has signified that it's too busy (or its owner is a moron) because it is
+                // claiming it has no scripts at all.
+                if (DEBUGGING) {
+                    log_it("server " + (string)inventory_request_channel + " is too busy to update us now.");
+                }
+                // make it seem like we need to do this one again sooner than normal.
+                whack_updater_record(id);
+                // busy server means move no further forward.
+                return FALSE;
+            }
+            return initiate_update(message);
+        } else if (is_prefix(message, SHUT_THEM_DOWN)) {
+            if (DEBUGGING) { log_it("stopping other scripts."); }
+            knock_around_other_scripts(FALSE);
+            // now that we know for sure the server's ready to update us,
+            // we tell it what we need.
+            tell_server_our_wish_list();
+            return FALSE;
+        } else if (is_prefix(message, START_THEM_UP)) {
+            // let the server know that we've finished, for all intents and purposes.
+            llSay(update_channel, DONE_UPDATING);
+            // we pause a random bit first; we want to ensure we aren't swamping
+            // SL with our inventory loading.
+            llSleep(randomize_within_range(2.5, 8.2, FALSE));
+            if (DEBUGGING) { log_it("starting other scripts."); }
+            careful_crankup();
+            return TRUE;  // change state now.
+//        } else {
+//log_it("unknown command on update channel: " + message);
+        }
+    }
+    return FALSE;
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    llWhisper(0, llGetScriptName() + " [" + (string)debug_num + "] (" + (string)llGetFreeMemory() + ") " + to_say);
+}
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type, integer exact_match)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (exact_match && (llGetInventoryName(inv_type, inv) == name_to_find) )
+            return inv;
+        else if (!exact_match && is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+//////////////
+
+integer MAX_CHAT_LINE = 900;
+    // the most characters we'll try to say in one chat.
+
+dump_list_to_log(list to_show)
+{
+    string text = dump_list(to_show);  // get some help from the other version.
+    integer len = llStringLength(text);
+    integer i;
+    for (i = 0; i < len; i += MAX_CHAT_LINE) {
+        integer last_bit = i + MAX_CHAT_LINE - 1;
+        if (last_bit >= len) last_bit = len - 1;
+        string next_line = llGetSubString(text, i, last_bit);
+        llWhisper(0, next_line);
+    }
+}
+
+// returns a printable form of the list.
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = 0; i < len; i++) {
+        string next_line = llList2String(to_show, i);
+        if (find_substring(next_line, " ") >= 0) {
+            // this guy has a space in it, so quote it.
+            next_line = "\"" + next_line + "\"";
+        }
+        text = text + next_line;
+        if (i < len - 1) text = text + " ";
+    }
+    return text;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+// no huffotronic trap state for startup, because this script will actually
+// run (and is expected) inside a huffotronic updater object.
+
+default
+{
+    state_entry()
+    {
+        auto_retire();  // only allow the most recent revision.
+        initialize();
+        state awaiting_commands;
+    }
+}
+
+state awaiting_commands
+{
+    state_entry()
+    {
+        if (DEBUGGING) log_it("<awaiting_commands>");
+        careful_crankup();  // we always start by getting everyone running.
+        current_server = NULL_KEY;  // forget previous server.
+        listen_for_orders(FALSE);
+        inventory_request_channel = 0;  // no inventory request channel either.
+        update_channel = 0;  // no channel currently.
+        updates_needed = [];  // we know of no needs right now.
+        known_script_dependencies = [];  // no deps either.
+    }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message))
+            state establish_private_channel;
+    }
+}
+
+state establish_private_channel
+{
+    state_entry()
+    {
+        if (DEBUGGING) log_it("<establish_private_channel>");
+        llListen(update_channel, "", current_server, "");
+        listen_for_orders(TRUE);
+        if (inventory_request_channel)
+            llSay(inventory_request_channel, REQUEST_INVENTORY_PREFIX + (string)update_channel);
+        else
+            llSay(OLD_REQUEST_INVENTORY_CHANNEL, REQUEST_INVENTORY_PREFIX + (string)update_channel);
+        llSetTimerEvent(MAXIMUM_UPDATE_TIME_ALLOWED);
+    }
+
+    state_exit() { llSetTimerEvent(0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message)) {
+            // ready for a state change, but what kind?
+            if (llGetListLength(updates_needed)) {
+//log_it("have a list of updates now.");
+                state performing_update;
+            } else {
+//log_it("no updates needed in list, going back");
+                state awaiting_commands;
+            }
+        }
+    }
+    
+    timer() {
+        if (DEBUGGING) {
+            log_it("timed out establishing channel with server " + (string)inventory_request_channel);
+        }
+        whack_updater_record(current_server);
+        state awaiting_commands;
+    }
+
+    on_rez(integer parm) { state default; }
+}
+
+state performing_update
+{
+    state_entry()
+    {
+        // must re-listen after a state change.
+        llListen(update_channel, "", current_server, "");
+        listen_for_orders(TRUE);
+        if (DEBUGGING) log_it("<performing_update>");
+        llSetTimerEvent(UPDATE_TIMER_INTERVAL);
+        update_start_time = llGetUnixTime();
+    }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message)) {
+            // normal finish of update process.
+            state awaiting_commands;
+        }
+    }
+
+    timer() {
+        if (llGetListLength(updates_needed) == 0) {
+//log_it("nothing to update, leaving perform state.");
+            state awaiting_commands;  // we've got nothing to do.
+        } else {
+            // see if all our requested scripts are there yet; if not, we're not done updating.
+            integer ready = check_on_update_presence();
+            if (ready) {
+                if (DEBUGGING) log_it("reporting scripts are current.");
+                llSay(update_channel, SCRIPTS_ARE_CURRENT);
+            }
+        }
+        if (llAbs(update_start_time - llGetUnixTime()) >= MAXIMUM_UPDATE_TIME_ALLOWED) {
+            if (DEBUGGING) { log_it("timeout during update process with server " + (string)inventory_request_channel); }
+            whack_updater_record(current_server);
+            state awaiting_commands;
+        }
+    }
+
+    on_rez(integer parm) { state default; }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/huff-update_client_v20.1.txt b/huffware/huffotronic_jaunter_updater_v5.1/huff-update_client_v20.1.txt
deleted file mode 100755 (executable)
index 4a458bb..0000000
+++ /dev/null
@@ -1,826 +0,0 @@
-
-// huffware script: huff-update client, by fred huffhines.
-//
-// this script is the client side of the update process.  it should reside in an object that
-// has scripts which should be automatically updated.  it will listen for announcements by
-// an update server and communicate with the server to ensure that all of its scripts are
-// the most up to date available with the server.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-integer DEBUGGING = FALSE;  // if TRUE, the script will output status information.
-
-integer SERVER_IGNORE_TIME = 1200;  // number of seconds between performing an upgrade with the same server.
-
-integer MAXIMUM_UPDATE_TIME_ALLOWED = 140;  // we allow one upgrade process to take this long overall.
-
-integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
-integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
-
-string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
-string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
-string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
-string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
-string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
-string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
-string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
-string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
-string DONE_UPDATING                = "#finito#";  // the client is done updating.
-string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
-
-float UPDATE_TIMER_INTERVAL = 2.0;  // interval between checks on our update status.
-
-integer UPDATER_SCRIPT_PIN = -1231008;  // the hook for our scripts to be modified.
-
-///float BUSY_SERVER_PAUSE_TIME = 38.0;  // num seconds to delay when server says it's too busy.
-
-string UPDATER_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-
-string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
-string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
-
-integer MAXIMUM_SERVERS_TRACKED = 32;
-    // we will listen to this many servers before we decide to remove one.
-
-string CONTINUANCE_MARKER = "...";
-    // a string sent when the update list is too long and needs to be continued in another chat.
-
-string SERVER_SCRIPT = "a huffotronic update server";
-    // the prefix of our server script that hands out updates.
-
-// global variables...
-
-integer inventory_request_channel;  // used for newer version servers to cut down cross chatter.
-list updaters_heard;  // the update servers we've heard from recently.
-list last_interactions;  // times of the last update process engaged with the updater.
-integer update_channel;  // current channel for interaction with specific server.
-key current_server;  // the updater that is active right now, if any.
-integer update_start_time;  // when the last update process began.
-list updates_needed;  // stores the set of scripts that are in need of an update.
-list known_script_dependencies;  // stores the list of dependency info.
-
-careful_crankup()
-{
-    knock_around_other_scripts(TRUE);
-    // clean out the older items and scripts.  we do this after getting everyone running
-    // since we might be whacking ourselves.
-    destroy_older_versions();
-}
-
-// reset our variables.
-initialize()
-{
-    updaters_heard = [];
-    last_interactions = [];
-    inventory_request_channel = 0;
-    update_channel = 0;
-    current_server = NULL_KEY;
-    llSetTimerEvent(0.0);
-    llSetRemoteScriptAccessPin(UPDATER_SCRIPT_PIN);
-    // a new enhancements; tells the server that this guy has finished an update cycle.  this
-    // only comes into play when the updater script itself has just been updated, but it's
-    // nice for the server to avoid claiming erroneous timeouts occurred.
-    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
-    llSleep(0.4);  // snooze and repeat to overcome occasionally lossy chats.
-    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
-}
-
-whack_updater_record(key id)
-{
-    integer prev_indy = find_in_list(updaters_heard, id);
-    if (prev_indy < 0) return;  // not there.
-    updaters_heard = chop_list(updaters_heard, 0, prev_indy - 1)
-            + chop_list(updaters_heard, prev_indy + 1, llGetListLength(updaters_heard) - 1);
-    last_interactions = chop_list(last_interactions, 0, prev_indy - 1)
-            + chop_list(last_interactions, prev_indy + 1, llGetListLength(last_interactions) - 1);
-}
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        if (DEBUGGING)
-            log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-    // thirdly, try to clean out the notecards.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
-}
-
-// sets the object to be listening for update info.
-// if "just_owner" is true, then we will not listen on the general announcement channel.
-listen_for_orders(integer just_owner)
-{
-    if (!just_owner) {
-        // try to hear an update being announced.
-        llListen(UPDATE_ANNOUNCEMENT_CHANNEL, "", NULL_KEY, "");
-    }
-
-    // super secret owner controls.
-    llListen(0, "", llGetOwner(), "");
-}
-
-// returns true if this object is a huffotronic updater of some sort.
-integer inside_of_updater()
-{
-    return find_substring(llGetObjectName(), "huffotronic") >= 0;
-}
-
-// returns true if a script is a version of our update server.
-integer matches_server_script(string to_check)
-{
-    return is_prefix(to_check, SERVER_SCRIPT);
-}
-
-// stops all the scripts besides this one.
-knock_around_other_scripts(integer running_state)
-{
-    integer insider = inside_of_updater();
-    if (running_state == TRUE) {
-        // make sure we crank up the scripts that are new first.  we want to reset them
-        // as well, which we don't want to do for any existing scripts.
-        integer crank_indy;
-        for (crank_indy = 0; crank_indy < llGetListLength(updates_needed); crank_indy++) {
-            string crankee = llList2String(updates_needed, crank_indy);
-            if (find_in_inventory(crankee, INVENTORY_SCRIPT, TRUE) >= 0) {
-                if (!insider || matches_server_script(crankee)) {
-                    // allow it to run again.
-                    llSetScriptState(crankee, TRUE);
-                    // reset it, to make sure it starts at the top.
-                    llResetOtherScript(crankee);
-                }
-            }
-        }
-    }
-
-    integer indy;
-    string self_script = llGetScriptName();
-    // we set all other scripts to the running state requested.
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if ( (curr_script != self_script)
-            && (!insider || matches_server_script(curr_script)) ) {
-            // this one seems ripe for being set to the state requested.
-            llSetScriptState(curr_script, running_state);
-        }
-    }
-}
-
-// a random channel for the interaction with the server.
-integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
-
-// make sure that any dependencies for the script with "basename" are added to the list
-// of requests we make during an update.
-list add_dependencies(string basename)
-{
-    list to_return;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(known_script_dependencies); indy++) {
-        list deps = llParseString2List(llList2String(known_script_dependencies, indy),
-            [ITEM_LIST_SEPARATOR], []);
-//log_it("base=" + llList2String(dep, 0) + " lastver=" + llList2String(dep, 1) + " newdep=" + llList2String(dep, 2));
-        if (basename == llList2String(deps, 0)) {
-            // first off, is this item with new dependencies actually present?
-            integer where = find_in_inventory(basename, INVENTORY_SCRIPT, FALSE);
-            if (where >= 0) {
-                // we do use the script with deps, but is the dependent item really missing?
-                where = find_in_inventory(llList2String(deps, 1), INVENTORY_SCRIPT, FALSE);
-                if (where < 0) {
-                    // we found a dependency match for this script, so we'll ask for the missing item.
-                    if (DEBUGGING)
-                        log_it("missing dep: " + llList2String(deps, 1));
-                    to_return += [ llList2String(deps, 1) ];
-                }
-            }
-        }
-    }
-    return to_return;
-}
-
-// complains if memory seems to be getting tight.
-test_memory()
-{
-    if (llGetFreeMemory() < 4096)
-        log_it("mem_free = " + (string)llGetFreeMemory());
-}
-
-// starts an update given a list of scripts that the server has available, encoded as
-// a string in the "encoded_list".
-integer initiate_update(string encoded_list)
-{
-    list scripts_avail = llParseString2List(encoded_list, [UPDATER_PARM_SEPARATOR], []);
-    integer continue_listening_for_scripts = FALSE;
-      // if true, we aren't done hearing about available scripts yet.
-    encoded_list = "";
-    // figure out which scripts we need by comparing the list available from the server
-    // against our current inventory.  we only want scripts with newer version numbers.
-    integer sindy;
-    for (sindy = 0; sindy < llGetListLength(scripts_avail); sindy++) {
-        string curr = llList2String(scripts_avail, sindy);
-        if (curr == CONTINUANCE_MARKER) {
-            // this is a special continuation signal.  we need to hear the rest of the list.
-            continue_listening_for_scripts = TRUE;
-        } else if (is_prefix(curr, SCRIPT_DEPENDENCY_MARK)) {
-            // we've found a dependency item.
-            known_script_dependencies += [ llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1) ];
-//log_it("script dep: " + llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1));
-        } else {
-            list split = compute_basename_and_version(curr);
-            if (llGetListLength(split) == 2) {
-                string basename = llList2String(split, 0);
-                string version = llList2String(split, 1);
-                split = [];
-                integer oy_indy;
-//replace common code with func.
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_OBJECT); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_OBJECT, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-//                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-//                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_NOTECARD); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_NOTECARD, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_SCRIPT); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_SCRIPT, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                updates_needed += add_dependencies(basename);
-            }
-        }
-    }
-    // we skip the next step if we're still waiting to hear about more.
-    if (continue_listening_for_scripts) {
-//log_it("still listening for more updates...");
-        return FALSE;
-    }
-    if (llGetListLength(updates_needed)) {
-//log_it("update chan=" + (string)update_channel);
-        llSay(update_channel, REQUEST_SCRIPT_UPDATE);
-        if (DEBUGGING) {
-            log_it("told server " + (string)inventory_request_channel + " that i need updating.");
-        }
-    } else {
-        if (DEBUGGING) {
-            log_it("told server " + (string)inventory_request_channel + " that i am done updating.");
-        }
-        llSay(update_channel, DONE_UPDATING);
-    }
-    return TRUE;
-}    
-
-// this alerts the server to our most desired scripts.
-tell_server_our_wish_list()
-{
-    llSay(update_channel, READY_TO_UPDATE + wrap_parameters(updates_needed));
-}
-
-// checks whether all of the updates needed are present yet.
-integer check_on_update_presence()
-{
-    integer indy;
-    for (indy = 0; indy < llGetListLength(updates_needed); indy++) {
-        integer found = find_in_inventory(llList2String(updates_needed, indy), INVENTORY_ALL, TRUE);
-        // any single missing guy means they aren't up to date yet.
-        if (found < 0) {
-            if (DEBUGGING) log_it(llList2String(updates_needed, indy) + " not seen as updated yet.");
-            return FALSE;
-        }
-    }
-    // nothing was detected as missing anymore.
-    return TRUE;
-}
-
-// respond to spoken commands from the server.
-integer process_update_news(integer channel, string name, key id, string message)
-{
-    if (!channel) {
-        // this is a command.
-        if (message == "ureset") {
-            llResetScript();  // start over.
-        }
-        if (message == "ushow") {
-            integer sindy;
-            integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
-            list script_list = [ "scripts--" ];  // first item is just a header.
-            for (sindy = 0; sindy < script_count; sindy++) {
-                script_list += [ llGetInventoryName(INVENTORY_SCRIPT, sindy) ];
-            }
-            dump_list_to_log(script_list);
-        }
-        return FALSE;  // nothing to do here.
-    }
-    if (!update_channel && (channel == UPDATE_ANNOUNCEMENT_CHANNEL)) {
-/* never seen.        if (id == llGetKey()) {
-if (DEBUGGING) log_it("ignoring update from self.");            
-            return FALSE;  // ack, that's our very object.
-        }
-*/
-        if (llStringLength(message) > llStringLength(UPDATE_ANNOUNCEMENT_PREFIX)) {
-            // this is a new style update message.  we can set a different request channel.
-            string just_chan = llDeleteSubString(message, 0, llStringLength(UPDATE_ANNOUNCEMENT_PREFIX) - 1);
-            inventory_request_channel = (integer)just_chan;
-        }
-        integer prev_indy = find_in_list(updaters_heard, id);
-        // find the talker in our list.
-        if (prev_indy >= 0) {
-            // that guy was already heard from.  check when last interacted.
-            integer last_heard = llList2Integer(last_interactions, prev_indy);
-            if (llAbs(llGetUnixTime() - last_heard) < SERVER_IGNORE_TIME) {
-                return FALSE;  // not time to update with this guy again yet.
-            }
-//            if (DEBUGGING) { log_it("started listening again to server " + (string)id); }
-            // make sure we think of this as a new updater now.
-            whack_updater_record(id);
-        }
-
-        if (DEBUGGING) { log_it("heard server " + (string)inventory_request_channel + "'s announcement."); }
-        // record our new server.
-        current_server = id;
-        // make a random pause so not all updaters try to crank up at same time.
-        llSleep(randomize_within_range(2.8, 18.2, FALSE));
-
-        if (llGetListLength(updaters_heard) > MAXIMUM_SERVERS_TRACKED) {
-            // oops, this is not good.  we have too many servers now.
-//hmmm: room for improvement here by tossing out the server that is oldest.
-            updaters_heard = llDeleteSubList(updaters_heard, 0, 0);
-            last_interactions = llDeleteSubList(last_interactions, 0, 0);
-        }
-        
-        // add the talker to our list.
-        updaters_heard += id;
-        last_interactions += llGetUnixTime();
-    
-        // begin the update interaction with this guy.
-        update_channel = random_channel();
-        return TRUE;
-    }
-    if (update_channel && (channel == update_channel) ) {
-        if (is_prefix(message, REPORT_AVAILABLE_SCRIPTS)) {
-            // tasty, this is a list of scripts that can be had.
-            message = llDeleteSubString(message, 0, llStringLength(REPORT_AVAILABLE_SCRIPTS) - 1);
-            if (message == BUSY_BUSY) {
-                // server has signified that it's too busy (or its owner is a moron) because it is
-                // claiming it has no scripts at all.
-                if (DEBUGGING) {
-                    log_it("server " + (string)inventory_request_channel + " is too busy to update us now.");
-                }
-                // make it seem like we need to do this one again sooner than normal.
-                whack_updater_record(id);
-                // busy server means move no further forward.
-                return FALSE;
-            }
-            return initiate_update(message);
-        } else if (is_prefix(message, SHUT_THEM_DOWN)) {
-            if (DEBUGGING) { log_it("stopping other scripts."); }
-            knock_around_other_scripts(FALSE);
-            // now that we know for sure the server's ready to update us,
-            // we tell it what we need.
-            tell_server_our_wish_list();
-            return FALSE;
-        } else if (is_prefix(message, START_THEM_UP)) {
-            // let the server know that we've finished, for all intents and purposes.
-            llSay(update_channel, DONE_UPDATING);
-            // we pause a random bit first; we want to ensure we aren't swamping
-            // SL with our inventory loading.
-            llSleep(randomize_within_range(2.5, 8.2, FALSE));
-            if (DEBUGGING) { log_it("starting other scripts."); }
-            careful_crankup();
-            return TRUE;  // change state now.
-//        } else {
-//log_it("unknown command on update channel: " + message);
-        }
-    }
-    return FALSE;
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    llWhisper(0, llGetScriptName() + " [" + (string)debug_num + "] (" + (string)llGetFreeMemory() + ") " + to_say);
-}
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type, integer exact_match)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (exact_match && (llGetInventoryName(inv_type, inv) == name_to_find) )
-            return inv;
-        else if (!exact_match && is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-//////////////
-
-integer MAX_CHAT_LINE = 900;
-    // the most characters we'll try to say in one chat.
-
-dump_list_to_log(list to_show)
-{
-    string text = dump_list(to_show);  // get some help from the other version.
-    integer len = llStringLength(text);
-    integer i;
-    for (i = 0; i < len; i += MAX_CHAT_LINE) {
-        integer last_bit = i + MAX_CHAT_LINE - 1;
-        if (last_bit >= len) last_bit = len - 1;
-        string next_line = llGetSubString(text, i, last_bit);
-        llWhisper(0, next_line);
-    }
-}
-
-// returns a printable form of the list.
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = 0; i < len; i++) {
-        string next_line = llList2String(to_show, i);
-        if (find_substring(next_line, " ") >= 0) {
-            // this guy has a space in it, so quote it.
-            next_line = "\"" + next_line + "\"";
-        }
-        text = text + next_line;
-        if (i < len - 1) text = text + " ";
-    }
-    return text;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-// no huffotronic trap state for startup, because this script will actually
-// run (and is expected) inside a huffotronic updater object.
-
-default
-{
-    state_entry()
-    {
-        auto_retire();  // only allow the most recent revision.
-        initialize();
-        state awaiting_commands;
-    }
-}
-
-state awaiting_commands
-{
-    state_entry()
-    {
-        if (DEBUGGING) log_it("<awaiting_commands>");
-        careful_crankup();  // we always start by getting everyone running.
-        current_server = NULL_KEY;  // forget previous server.
-        listen_for_orders(FALSE);
-        inventory_request_channel = 0;  // no inventory request channel either.
-        update_channel = 0;  // no channel currently.
-        updates_needed = [];  // we know of no needs right now.
-        known_script_dependencies = [];  // no deps either.
-    }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message))
-            state establish_private_channel;
-    }
-}
-
-state establish_private_channel
-{
-    state_entry()
-    {
-        if (DEBUGGING) log_it("<establish_private_channel>");
-        llListen(update_channel, "", current_server, "");
-        listen_for_orders(TRUE);
-        if (inventory_request_channel)
-            llSay(inventory_request_channel, REQUEST_INVENTORY_PREFIX + (string)update_channel);
-        else
-            llSay(OLD_REQUEST_INVENTORY_CHANNEL, REQUEST_INVENTORY_PREFIX + (string)update_channel);
-        llSetTimerEvent(MAXIMUM_UPDATE_TIME_ALLOWED);
-    }
-
-    state_exit() { llSetTimerEvent(0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message)) {
-            // ready for a state change, but what kind?
-            if (llGetListLength(updates_needed)) {
-//log_it("have a list of updates now.");
-                state performing_update;
-            } else {
-//log_it("no updates needed in list, going back");
-                state awaiting_commands;
-            }
-        }
-    }
-    
-    timer() {
-        if (DEBUGGING) {
-            log_it("timed out establishing channel with server " + (string)inventory_request_channel);
-        }
-        whack_updater_record(current_server);
-        state awaiting_commands;
-    }
-
-    on_rez(integer parm) { state default; }
-}
-
-state performing_update
-{
-    state_entry()
-    {
-        // must re-listen after a state change.
-        llListen(update_channel, "", current_server, "");
-        listen_for_orders(TRUE);
-        if (DEBUGGING) log_it("<performing_update>");
-        llSetTimerEvent(UPDATE_TIMER_INTERVAL);
-        update_start_time = llGetUnixTime();
-    }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message)) {
-            // normal finish of update process.
-            state awaiting_commands;
-        }
-    }
-
-    timer() {
-        if (llGetListLength(updates_needed) == 0) {
-//log_it("nothing to update, leaving perform state.");
-            state awaiting_commands;  // we've got nothing to do.
-        } else {
-            // see if all our requested scripts are there yet; if not, we're not done updating.
-            integer ready = check_on_update_presence();
-            if (ready) {
-                if (DEBUGGING) log_it("reporting scripts are current.");
-                llSay(update_channel, SCRIPTS_ARE_CURRENT);
-            }
-        }
-        if (llAbs(update_start_time - llGetUnixTime()) >= MAXIMUM_UPDATE_TIME_ALLOWED) {
-            if (DEBUGGING) { log_it("timeout during update process with server " + (string)inventory_request_channel); }
-            whack_updater_record(current_server);
-            state awaiting_commands;
-        }
-    }
-
-    on_rez(integer parm) { state default; }
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunt_config_funcs_v2.9.lsl b/huffware/huffotronic_jaunter_updater_v5.1/jaunt_config_funcs_v2.9.lsl
new file mode 100755 (executable)
index 0000000..c09890c
--- /dev/null
@@ -0,0 +1,494 @@
+
+// huffware script: jaunt config funcs, by fred huffhines, released under GPL license.
+//
+// this is the part of the jaunt wik rez ensemble that deals with configuration.
+// it reads the configuration from notecards and passes it to the main script.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+
+integer DEBUGGING = FALSE;
+    // make this true for noisy runtime diagnostics.
+
+// defines the jaunt config funcs messaging API.
+//////////////
+// do not redefine these constants.
+integer JAUNT_CONFIGURATION_HUFFWARE_ID = 10022;
+    // the unique id within the huffware system for this script's commands.
+    // it's used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+// commands available from the jaunt config library:
+string LOAD_ALL_CONFIGURATIONS = "#rdcfg#";
+    // this starts the process of loading jaunt destinations from the notecards and
+    // landmarks that we find in the object.  the parms are: private channel
+    // and conveyance mode.
+string JAUNT_CFG_DATA_EVENT = "#yodata#";
+    // this event is generated from this script back to the caller.  when we have some
+    // landmark data or configuration information, it's passed back in chunks.  the
+    // deluge of pieces will continue until the JAUNT_CFG_EOF event is passed.  the
+    // parameters include packed destination name and vector pairs (which form 2 elements
+    // in the list) and packed config variable definitions (where config items start
+    // with a colon, and the definition is only one element in the list).
+string JAUNT_CFG_EOF = "#done#";
+    // sent after all valid configuration items that we could find were processed.  there
+    // are no parameters for this command.
+//
+//////////////
+
+// important constants used internally...  these should generally not be changed.
+
+// indicates a reconnaissance command when found as a prefix on chat text
+// on our official recon channel.
+string RECON_TEXT = "#rcn";
+string READY_TEXT = "-y";  // lets us know that a jaunter is ready to be filled.
+string RETURN_WORD = "-b";  // used to signal a returning recong jaunter.
+
+integer MAXIMUM_BLAST_SIZE = 6;  // maximum number of config items per blurt.
+
+integer TIMEOUT_FOR_CONFIGURATION_PROCESS = 42;
+    // how long the notecard and lm reading processes are allowed to last.
+
+integer TWO_WAY_TRIP = 1;
+integer AUTOREZ_JAUNTER = 2;
+integer ONE_WAY_TRIP = 3;
+integer RECONNAISSANCE_TRIP = 4;
+
+string DB_SEPARATOR = "``";  // separating items in lists.
+
+//////////////
+
+// global variables.
+
+integer unused_private_chat_channel;  // where sub-jaunters communicate with root.
+
+integer conveyance_mode;  //// = TWO_WAY_TRIP;
+    // default is a standard two way trip, there and back again.  note that the object
+    // will fail to return if any lands in between are blocking object entry.  those
+    // situations should use an auto-rez jaunter, which is specified by prefixing the
+    // target vectors with AR.
+
+////integer current_target_index;  // the location in the list that we would currently jaunt to.
+
+list config_to_blast;  // what we will send to our client.
+
+// notecard variables...
+integer response_code;  // set to uniquely identify the notecard read in progress.
+string leftover_parms;  // items leftover during config.
+
+// lm variables...
+integer current_lm;
+key lm_data_req;  // this is the current landmark being served as data.
+
+//////////////
+
+// requires noteworthy library v5.4 or higher.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+//string BUSY_READING_INDICATOR = "busy_already";
+    // this return value indicates that the script is already in use by some other script.
+    // the calling script should try again later.
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the only parameter.  the signature can be empty or missing.
+    // the results will be fired back as the string value returned, which will have
+    // an embedded list that was read from the notecard.  this necessarily limits the
+    // size of the notecards that we can read and return.
+//
+//////////////
+
+// begins getting configuration items from notecards and landmarks.
+start_reading_configuration()
+{
+    llSetTimerEvent(0.0);  // cancel any existing timers.
+
+    string JAUNT_SIGNATURE = "#jaunt";  // the expected first line of our notecards.
+
+    // a normal startup where we read notecards and stuff...
+    // see if we can load a notecard for destinations.
+    response_code = random_channel();
+    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+         wrap_parameters([JAUNT_SIGNATURE, response_code]));
+    // we pick a private channel that fits in between our rez parm ranges.
+    // during a normal trip, we will make sure the notecard reading doesn't stall.
+    // the recon and one way jaunters don't need this; they're temporary.
+    // we allow this number of seconds before notecard reader is awol.
+
+    llSetTimerEvent(TIMEOUT_FOR_CONFIGURATION_PROCESS);
+}
+
+// main API implementor; answers requests to start reading config.
+handle_config_request(string msg, string id)
+{
+    if (msg != LOAD_ALL_CONFIGURATIONS) return;  // not for us.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    // set our variables from the parameters we were given.
+    unused_private_chat_channel = llList2Integer(parms, 0);
+    conveyance_mode = llList2Integer(parms, 1);
+    if ( (conveyance_mode != RECONNAISSANCE_TRIP) && (conveyance_mode != ONE_WAY_TRIP) ) {
+        // setting up a root jaunter.
+        start_reading_configuration();
+    }
+}
+
+// sends out our current configuration perhaps.  if the check_length flag is true,
+// then we'll only send if the list is already too fat.  if the flag is false, then
+// we always just send our config (if it's non-empty).
+send_config_blast(integer check_length)
+{
+    if (!check_length || (llGetListLength(config_to_blast) > MAXIMUM_BLAST_SIZE) ) {
+        if (llGetListLength(config_to_blast) > 0) {
+            llMessageLinked(LINK_THIS, JAUNT_CONFIGURATION_HUFFWARE_ID + REPLY_DISTANCE,
+                JAUNT_CFG_DATA_EVENT, wrap_parameters(config_to_blast));
+            config_to_blast = [];
+        }
+    }
+}
+
+// deals with responses from the notecard library.
+process_notecard_lines(string msg, string id)
+{
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    if (llList2Integer(parms, 1) != response_code) return;  // this isn't for us.
+
+    integer totally_done = TRUE;  // if left set to true, then notecard is done being consumed.
+    
+    string note_name = llList2String(parms, 0);
+    if (DEBUGGING) log_it("note name: " + note_name);
+    parms = llDeleteSubList(parms, 0, 1);
+    
+    // add in the leftovers.
+    if (leftover_parms != "") {
+        if (DEBUGGING) log_it("added leftover: " + leftover_parms);
+        parms = [ leftover_parms ] + parms;
+        leftover_parms = "";
+    }
+
+    if (note_name == NOTECARD_READ_CONTINUATION) {
+        totally_done = FALSE;
+        if (DEBUGGING) log_it("not totally done reading yet.");
+    }
+    if (note_name != BAD_NOTECARD_INDICATOR) {
+        integer indy;
+        for (indy = 0; indy < llGetListLength(parms); indy++) {
+            if (DEBUGGING) log_it("index: " + (string)indy);
+            string targ = llList2String(parms, indy);
+            if (DEBUGGING) log_it("targ: " + targ);
+            if (is_prefix(targ, ":")) {
+                if (DEBUGGING) log_it("targ is special command.  just adding.");
+                config_to_blast += [ targ ];
+            } else {
+                if (indy < llGetListLength(parms) - 1) {
+                    if (DEBUGGING) log_it("decided we can steal two items.");
+                    // this looks like a normal pair of destination vector and name.
+                    string the_name = prune_name(llList2String(parms, indy + 1));
+                    config_to_blast += [ the_name, targ ];
+                    if (DEBUGGING) log_it("stole: " + the_name + " --> " + targ);
+                    indy++;  // skip an extra index since we stole two.
+                } else {
+                    // save this tidbit for next config cycle.
+                    if (DEBUGGING) log_it("saving tidbit for next round: " + targ);
+                    leftover_parms = targ;
+                }
+            }
+            send_config_blast(TRUE);
+        }
+    }
+
+    if (totally_done) {
+        // now that we've gotten our notecard read in, check the landmarks in
+        // the inventory to see if they're useful.
+        current_lm = 0;
+        if (current_lm < llGetInventoryNumber(INVENTORY_LANDMARK)) {
+            lm_data_req = llRequestInventoryData(
+                llGetInventoryName(INVENTORY_LANDMARK, current_lm));
+        } else {
+            // kick out of this state and signal completion.
+            llSetTimerEvent(0.001);
+        }
+    }
+}
+
+// report our getting configured properly.
+completed_configuration()
+{
+    send_config_blast(FALSE);  // get last of config bits out to the client.
+    llMessageLinked(LINK_THIS, JAUNT_CONFIGURATION_HUFFWARE_ID + REPLY_DISTANCE,
+        JAUNT_CFG_EOF, NULL_KEY);
+}
+
+// fixes a location name so we don't get crushed on memory usage.
+string prune_name(string to_prune)
+{
+    integer MAX_DEST_NAME = 28;  // the longest name that we store.
+
+    // see if we can strip off the locational info.  comma is a common separator for stuff that's
+    // not part of the lm name.
+    integer indy = find_substring(to_prune, ",");
+    if (indy > 5) to_prune = llGetSubString(to_prune, 0, indy - 1);
+    // parentheses are another common way of adding extra stuff we don't need for the name.
+    indy = find_substring(to_prune, "(");
+    if (indy > 5) to_prune = llGetSubString(to_prune, 0, indy - 1);
+    // crop the name on general length issues too.
+    to_prune = llGetSubString(to_prune, 0, MAX_DEST_NAME);
+    return to_prune;
+}
+
+// called when dataserver brings us landmark info.
+process_landmark_data(key id, string data)
+{
+    if (id != lm_data_req) return;  // not for us.
+    lm_data_req = NULL_KEY;  // drop our prior key.
+    if (data != EOF) {
+        string dest = vector_chop((vector)data);
+        config_to_blast += [ prune_name(llGetInventoryName(INVENTORY_LANDMARK, current_lm)), dest ];
+        send_config_blast(TRUE);
+        current_lm++;
+        if (current_lm < llGetInventoryNumber(INVENTORY_LANDMARK)) {
+            lm_data_req = llRequestInventoryData(
+                llGetInventoryName(INVENTORY_LANDMARK, current_lm));
+        }
+    }
+    // check our sentinel data key about being done.
+    if (lm_data_req == NULL_KEY) {
+        // looks like we got our destinations and are totally done now.
+        llSetTimerEvent(0.001);  // trigger state change very shortly.
+    }
+}
+
+//////////////
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+///////////////
+
+// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
+integer valid_sim_value(float to_check)
+{
+    if (to_check < 0.0) return FALSE;
+    if (to_check >= 257.0) return FALSE;
+    return TRUE;
+}
+
+// returns TRUE if the "to_check" vector is a location outside of the current sim.
+integer outside_of_sim(vector to_check)
+{
+    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
+}
+
+// returns text for a floating point number, but includes only
+// three digits after the decimal point.
+string float_chop(float to_show)
+{
+    integer mant = llAbs(llRound(to_show * 1000.0) / 1000);
+    string neg_sign;
+    if (to_show < 0.0) neg_sign = "-";
+    string dec_s = (string)((llRound(to_show * 1000.0) - mant * 1000) / 1000.0);
+    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
+    // strip off all trailing zeros.
+    while (llGetSubString(dec_s, -1, -1) == "0")
+        dec_s = llDeleteSubString(dec_s, -1, -1);
+    string to_return = neg_sign + (string)mant;
+    if (llStringLength(dec_s)) to_return += "." + dec_s;
+    return to_return;
+}
+
+// returns a prettier form for vector text, with chopped floats.
+string vector_chop(vector to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ">";
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+
+integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{
+    string full_lower = llToLower(full_string);
+    return llSubStringIndex(full_lower, pattern);
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//////////////
+
+// default state scrounges for information in a notecard and looks for landmarks in
+// inventory to add as destinations.
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); }
+
+    link_message(integer which, integer num, string msg, key id)
+    {
+        if (num == NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE) {
+            process_notecard_lines(msg, id);
+        } else if (num == JAUNT_CONFIGURATION_HUFFWARE_ID) {
+            handle_config_request(msg, id);
+        }
+    }
+    
+    dataserver(key id, string data) { process_landmark_data(id, data); }
+
+    timer() {
+        // this is the only place we publish a result.
+        completed_configuration();
+        llSetTimerEvent(0.0);  // stop the timer again, until next request.
+    }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunt_config_funcs_v2.9.txt b/huffware/huffotronic_jaunter_updater_v5.1/jaunt_config_funcs_v2.9.txt
deleted file mode 100755 (executable)
index c09890c..0000000
+++ /dev/null
@@ -1,494 +0,0 @@
-
-// huffware script: jaunt config funcs, by fred huffhines, released under GPL license.
-//
-// this is the part of the jaunt wik rez ensemble that deals with configuration.
-// it reads the configuration from notecards and passes it to the main script.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-
-integer DEBUGGING = FALSE;
-    // make this true for noisy runtime diagnostics.
-
-// defines the jaunt config funcs messaging API.
-//////////////
-// do not redefine these constants.
-integer JAUNT_CONFIGURATION_HUFFWARE_ID = 10022;
-    // the unique id within the huffware system for this script's commands.
-    // it's used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-// commands available from the jaunt config library:
-string LOAD_ALL_CONFIGURATIONS = "#rdcfg#";
-    // this starts the process of loading jaunt destinations from the notecards and
-    // landmarks that we find in the object.  the parms are: private channel
-    // and conveyance mode.
-string JAUNT_CFG_DATA_EVENT = "#yodata#";
-    // this event is generated from this script back to the caller.  when we have some
-    // landmark data or configuration information, it's passed back in chunks.  the
-    // deluge of pieces will continue until the JAUNT_CFG_EOF event is passed.  the
-    // parameters include packed destination name and vector pairs (which form 2 elements
-    // in the list) and packed config variable definitions (where config items start
-    // with a colon, and the definition is only one element in the list).
-string JAUNT_CFG_EOF = "#done#";
-    // sent after all valid configuration items that we could find were processed.  there
-    // are no parameters for this command.
-//
-//////////////
-
-// important constants used internally...  these should generally not be changed.
-
-// indicates a reconnaissance command when found as a prefix on chat text
-// on our official recon channel.
-string RECON_TEXT = "#rcn";
-string READY_TEXT = "-y";  // lets us know that a jaunter is ready to be filled.
-string RETURN_WORD = "-b";  // used to signal a returning recong jaunter.
-
-integer MAXIMUM_BLAST_SIZE = 6;  // maximum number of config items per blurt.
-
-integer TIMEOUT_FOR_CONFIGURATION_PROCESS = 42;
-    // how long the notecard and lm reading processes are allowed to last.
-
-integer TWO_WAY_TRIP = 1;
-integer AUTOREZ_JAUNTER = 2;
-integer ONE_WAY_TRIP = 3;
-integer RECONNAISSANCE_TRIP = 4;
-
-string DB_SEPARATOR = "``";  // separating items in lists.
-
-//////////////
-
-// global variables.
-
-integer unused_private_chat_channel;  // where sub-jaunters communicate with root.
-
-integer conveyance_mode;  //// = TWO_WAY_TRIP;
-    // default is a standard two way trip, there and back again.  note that the object
-    // will fail to return if any lands in between are blocking object entry.  those
-    // situations should use an auto-rez jaunter, which is specified by prefixing the
-    // target vectors with AR.
-
-////integer current_target_index;  // the location in the list that we would currently jaunt to.
-
-list config_to_blast;  // what we will send to our client.
-
-// notecard variables...
-integer response_code;  // set to uniquely identify the notecard read in progress.
-string leftover_parms;  // items leftover during config.
-
-// lm variables...
-integer current_lm;
-key lm_data_req;  // this is the current landmark being served as data.
-
-//////////////
-
-// requires noteworthy library v5.4 or higher.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-//string BUSY_READING_INDICATOR = "busy_already";
-    // this return value indicates that the script is already in use by some other script.
-    // the calling script should try again later.
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the only parameter.  the signature can be empty or missing.
-    // the results will be fired back as the string value returned, which will have
-    // an embedded list that was read from the notecard.  this necessarily limits the
-    // size of the notecards that we can read and return.
-//
-//////////////
-
-// begins getting configuration items from notecards and landmarks.
-start_reading_configuration()
-{
-    llSetTimerEvent(0.0);  // cancel any existing timers.
-
-    string JAUNT_SIGNATURE = "#jaunt";  // the expected first line of our notecards.
-
-    // a normal startup where we read notecards and stuff...
-    // see if we can load a notecard for destinations.
-    response_code = random_channel();
-    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-         wrap_parameters([JAUNT_SIGNATURE, response_code]));
-    // we pick a private channel that fits in between our rez parm ranges.
-    // during a normal trip, we will make sure the notecard reading doesn't stall.
-    // the recon and one way jaunters don't need this; they're temporary.
-    // we allow this number of seconds before notecard reader is awol.
-
-    llSetTimerEvent(TIMEOUT_FOR_CONFIGURATION_PROCESS);
-}
-
-// main API implementor; answers requests to start reading config.
-handle_config_request(string msg, string id)
-{
-    if (msg != LOAD_ALL_CONFIGURATIONS) return;  // not for us.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    // set our variables from the parameters we were given.
-    unused_private_chat_channel = llList2Integer(parms, 0);
-    conveyance_mode = llList2Integer(parms, 1);
-    if ( (conveyance_mode != RECONNAISSANCE_TRIP) && (conveyance_mode != ONE_WAY_TRIP) ) {
-        // setting up a root jaunter.
-        start_reading_configuration();
-    }
-}
-
-// sends out our current configuration perhaps.  if the check_length flag is true,
-// then we'll only send if the list is already too fat.  if the flag is false, then
-// we always just send our config (if it's non-empty).
-send_config_blast(integer check_length)
-{
-    if (!check_length || (llGetListLength(config_to_blast) > MAXIMUM_BLAST_SIZE) ) {
-        if (llGetListLength(config_to_blast) > 0) {
-            llMessageLinked(LINK_THIS, JAUNT_CONFIGURATION_HUFFWARE_ID + REPLY_DISTANCE,
-                JAUNT_CFG_DATA_EVENT, wrap_parameters(config_to_blast));
-            config_to_blast = [];
-        }
-    }
-}
-
-// deals with responses from the notecard library.
-process_notecard_lines(string msg, string id)
-{
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    if (llList2Integer(parms, 1) != response_code) return;  // this isn't for us.
-
-    integer totally_done = TRUE;  // if left set to true, then notecard is done being consumed.
-    
-    string note_name = llList2String(parms, 0);
-    if (DEBUGGING) log_it("note name: " + note_name);
-    parms = llDeleteSubList(parms, 0, 1);
-    
-    // add in the leftovers.
-    if (leftover_parms != "") {
-        if (DEBUGGING) log_it("added leftover: " + leftover_parms);
-        parms = [ leftover_parms ] + parms;
-        leftover_parms = "";
-    }
-
-    if (note_name == NOTECARD_READ_CONTINUATION) {
-        totally_done = FALSE;
-        if (DEBUGGING) log_it("not totally done reading yet.");
-    }
-    if (note_name != BAD_NOTECARD_INDICATOR) {
-        integer indy;
-        for (indy = 0; indy < llGetListLength(parms); indy++) {
-            if (DEBUGGING) log_it("index: " + (string)indy);
-            string targ = llList2String(parms, indy);
-            if (DEBUGGING) log_it("targ: " + targ);
-            if (is_prefix(targ, ":")) {
-                if (DEBUGGING) log_it("targ is special command.  just adding.");
-                config_to_blast += [ targ ];
-            } else {
-                if (indy < llGetListLength(parms) - 1) {
-                    if (DEBUGGING) log_it("decided we can steal two items.");
-                    // this looks like a normal pair of destination vector and name.
-                    string the_name = prune_name(llList2String(parms, indy + 1));
-                    config_to_blast += [ the_name, targ ];
-                    if (DEBUGGING) log_it("stole: " + the_name + " --> " + targ);
-                    indy++;  // skip an extra index since we stole two.
-                } else {
-                    // save this tidbit for next config cycle.
-                    if (DEBUGGING) log_it("saving tidbit for next round: " + targ);
-                    leftover_parms = targ;
-                }
-            }
-            send_config_blast(TRUE);
-        }
-    }
-
-    if (totally_done) {
-        // now that we've gotten our notecard read in, check the landmarks in
-        // the inventory to see if they're useful.
-        current_lm = 0;
-        if (current_lm < llGetInventoryNumber(INVENTORY_LANDMARK)) {
-            lm_data_req = llRequestInventoryData(
-                llGetInventoryName(INVENTORY_LANDMARK, current_lm));
-        } else {
-            // kick out of this state and signal completion.
-            llSetTimerEvent(0.001);
-        }
-    }
-}
-
-// report our getting configured properly.
-completed_configuration()
-{
-    send_config_blast(FALSE);  // get last of config bits out to the client.
-    llMessageLinked(LINK_THIS, JAUNT_CONFIGURATION_HUFFWARE_ID + REPLY_DISTANCE,
-        JAUNT_CFG_EOF, NULL_KEY);
-}
-
-// fixes a location name so we don't get crushed on memory usage.
-string prune_name(string to_prune)
-{
-    integer MAX_DEST_NAME = 28;  // the longest name that we store.
-
-    // see if we can strip off the locational info.  comma is a common separator for stuff that's
-    // not part of the lm name.
-    integer indy = find_substring(to_prune, ",");
-    if (indy > 5) to_prune = llGetSubString(to_prune, 0, indy - 1);
-    // parentheses are another common way of adding extra stuff we don't need for the name.
-    indy = find_substring(to_prune, "(");
-    if (indy > 5) to_prune = llGetSubString(to_prune, 0, indy - 1);
-    // crop the name on general length issues too.
-    to_prune = llGetSubString(to_prune, 0, MAX_DEST_NAME);
-    return to_prune;
-}
-
-// called when dataserver brings us landmark info.
-process_landmark_data(key id, string data)
-{
-    if (id != lm_data_req) return;  // not for us.
-    lm_data_req = NULL_KEY;  // drop our prior key.
-    if (data != EOF) {
-        string dest = vector_chop((vector)data);
-        config_to_blast += [ prune_name(llGetInventoryName(INVENTORY_LANDMARK, current_lm)), dest ];
-        send_config_blast(TRUE);
-        current_lm++;
-        if (current_lm < llGetInventoryNumber(INVENTORY_LANDMARK)) {
-            lm_data_req = llRequestInventoryData(
-                llGetInventoryName(INVENTORY_LANDMARK, current_lm));
-        }
-    }
-    // check our sentinel data key about being done.
-    if (lm_data_req == NULL_KEY) {
-        // looks like we got our destinations and are totally done now.
-        llSetTimerEvent(0.001);  // trigger state change very shortly.
-    }
-}
-
-//////////////
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-///////////////
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-// returns TRUE if the "to_check" vector is a location outside of the current sim.
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-// returns text for a floating point number, but includes only
-// three digits after the decimal point.
-string float_chop(float to_show)
-{
-    integer mant = llAbs(llRound(to_show * 1000.0) / 1000);
-    string neg_sign;
-    if (to_show < 0.0) neg_sign = "-";
-    string dec_s = (string)((llRound(to_show * 1000.0) - mant * 1000) / 1000.0);
-    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
-    // strip off all trailing zeros.
-    while (llGetSubString(dec_s, -1, -1) == "0")
-        dec_s = llDeleteSubString(dec_s, -1, -1);
-    string to_return = neg_sign + (string)mant;
-    if (llStringLength(dec_s)) to_return += "." + dec_s;
-    return to_return;
-}
-
-// returns a prettier form for vector text, with chopped floats.
-string vector_chop(vector to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ">";
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{
-    string full_lower = llToLower(full_string);
-    return llSubStringIndex(full_lower, pattern);
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//////////////
-
-// default state scrounges for information in a notecard and looks for landmarks in
-// inventory to add as destinations.
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); }
-
-    link_message(integer which, integer num, string msg, key id)
-    {
-        if (num == NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE) {
-            process_notecard_lines(msg, id);
-        } else if (num == JAUNT_CONFIGURATION_HUFFWARE_ID) {
-            handle_config_request(msg, id);
-        }
-    }
-    
-    dataserver(key id, string data) { process_landmark_data(id, data); }
-
-    timer() {
-        // this is the only place we publish a result.
-        completed_configuration();
-        llSetTimerEvent(0.0);  // stop the timer again, until next request.
-    }
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunt_rezolator_v22.3.lsl b/huffware/huffotronic_jaunter_updater_v5.1/jaunt_rezolator_v22.3.lsl
new file mode 100755 (executable)
index 0000000..f7f7481
--- /dev/null
@@ -0,0 +1,1278 @@
+
+// huffware script: jaunt rezolator, by fred huffhines.
+//
+// this script supports the jaunt wik rez script by dealing with the rezzed objects.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants that can be changed to good effect.
+
+integer DEBUGGING = FALSE;  // set this to true for noisier run times.
+
+// important constants used internally...  these should not be changed willy nilly.
+
+// begin jaunt base API:
+
+// the following constants define how the script should behave (i.e., its conveyance mode).
+// TWO_WAY_TRIP: the script jaunts using the current target vectors to get somewhere
+//   and then takes the same pathway back, but in reverse order.
+// AUTOREZ_JAUNTER: the script rezzes the first regular object in its inventory next to
+//   the root telehub.  that object is loaded with the destination notecard and this script.
+//   the rezzed object can then be used for the next few minutes to jaunt to the selected
+//   destination.  the temporary object will use the ONE_WAY_TRIP mode.
+// ONE_WAY_TRIP: the object containing this script will take the user to a particular
+//   destination, but the object does not survive the trip.  it self-destructs after
+//   reaching the destination.  this mode is used in conjunction with the AUTOREZ_JAUNTER
+//   mode and should generally never be used on its own.
+// RECONNAISSANCE_TRIP: a survey run to test out a particular path to get to a
+//   destination.
+integer TWO_WAY_TRIP = 1;
+integer AUTOREZ_JAUNTER = 2;
+integer ONE_WAY_TRIP = 3;
+integer RECONNAISSANCE_TRIP = 4;
+
+// indicates a reconnaissance command when found as a prefix on chat text
+// on our official recon channel.
+string CHILD_CHAT_TEXT = "#rcn";
+string READY_TEXT = "-y";  // lets us know that a jaunter is ready to be filled.
+string RETURN_WORD = "-b";  // used to signal a returning recong jaunter.
+
+// values used to represent different stages of verification.
+integer VERIFY_UNTESTED = -3;  // don't know destinations tate yet.
+integer VERIFY_SAFE = -4;  // the destination last tested safe.
+integer VERIFY_UNSAFE_SO_FAR = -5;  // this cannot be done with simple jaunt.
+integer VERIFY_UNSAFE_DECIDED = -6;  // this means the destination seems intractable.
+
+integer ONE_WAY_TRICKY_PARM = -100000;
+    // used to signal to the one way jaunter that it's taking a single pathway.
+integer RECONNAISSANCE_TRICKY_PARM = -200000;
+    // on_rez parm indicates that this will be a recon trip to check out a path.
+integer MAXIMUM_PRIV_CHAN = 90000;
+    // the largest amount we will ever subtract from the tricky parms in order to
+    // tell the sub-jaunter which channel to listen on.
+
+string VECTOR_SEPARATOR = "|";
+    // how we separate components of vectors from each other.
+string DB_SEPARATOR = "``";  // separating items in lists.
+
+// end of jaunt base API.
+
+integer REZ_KID_FIELDS_NEEDED = 6;  // the rez kid API method needs this many parms.
+
+integer MAXIMUM_RECON_ATTEMPTS = 7;
+    // maximum tries to find a path for the hard cases (after first simple jaunt fails).
+
+float TIMER_PERIOD = 1.0;  // we run a pretty slow timer to check on destinations.
+
+integer MAXIMUM_SNOOZES = 20;  // how long we let a pending action go before declaring it failed.
+
+string OUR_COW_TAG = "l_jrzltr_dc";
+    // a hopefully unique id for this script to talk to the data cow with.
+
+// the actions that can be held in the action queue.
+integer AQ_ONEWAY_JAUNTER_VOYAGE = 40;  // information will be used for one-way jaunter.
+integer AQ_PREP_RECON_JAUNTER = 41;  // info for the reconnaissance jaunter to go check out.
+integer AQ_CHECK_HARD_CASE = 42;  // working on hard cases to get to destination somehow.
+integer AQ_ACQUIRE_BASE_PATH = 43;  // we are grabbing a random path that we think is healthy.
+
+string QUADRANT_TAG_NAME = "q:";  // a piece of text we put in front of generated destinations.
+
+integer MAXIMUM_SAFE_LOCATIONS = 28;  // we'll track this many extra locations.
+float MINIMUM_DISTANCE_FOR_EXTRAS = 10.0;  // how far a new locale must be to add.
+
+integer MAX_CHAT_REPEAT = 3;  // give instructions N times in case things are slow.
+float SLEEPY_TIME = 0.02;  // how long to snooze between chats.
+
+//////////////
+
+// global variables.
+
+list global_verifications;  // we gradually acquire knowledge of the health of the destinations.
+string global_object_name;  // the object to rez from inventory.
+string global_destination_name;  // the name of the place where the jaunter should go.
+vector global_rez_place;  // starting location for the rezzed jaunter.
+integer conveyance_mode;  // how the rezzed jaunter should process its destination.
+
+integer private_id_from_listen;  // set when we listen to our private channel.
+integer private_chat_channel;  // where sub-jaunters communicate with root.
+
+integer serving_root;  // if this is true, it means we are serving a root jaunter.
+
+integer destinations_total;  // how many destinations are known in total?  we compute this.
+integer destinations_real;  // how many are user-configured destinations?
+
+integer snooze_counter;  // how many times have we slept during a process?
+
+integer heard_from_root;  // true if the root jaunter has told us (a child jaunter) where to go.
+
+// recon variables...
+integer is_recon_pending;  // are we awaiting a reconnaissance?
+integer trying_hard_cases;  // are we already working on the tough ones?
+integer current_recon_index;  // where is the recon jaunter testing.
+integer recon_reattempts;  // how many tries did we take?
+integer done_reconnoiter;  // is recon process finished?
+integer succeeded_recon;  // set to true if close enough.
+integer good_destinations_counted;  // a tally of how many destinations looked healthy.
+integer ungenerated_good_destinations_counted;  // counts only user selected good dests.
+vector final_destination;  // where the recon process is really headed.
+integer partial_path_count;  // the counter for partial path replies.
+list safe_locales_seen;  // locations that we have a safe route to, as reported by recons.
+
+// jaunt trip variables...
+list full_journey;  // the full pathway we expect to jaunt on.
+integer last_verification;  // the last state we heard.
+
+// root jaunter variables...
+integer child_needs_setup;
+    // true when a child has been rezzed and still needs to be filled with the script.
+
+// the API for this library script to be used in other scripts.
+//////////////
+// do not redefine these constants.
+integer JAUNT_REZOLATOR_HUFFWARE_ID = 10025;
+    // the unique id within the huffware system for this script's commands.
+    // it's used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+// commands available from the library:
+string RESET_REZOLATOR = "#reset";
+    // tells the script to stop any previous efforts to rez children.
+string REZ_CHILD_NOW = "#rezkd#";
+    // requests this script to create a new child object.  this requires several
+    // parameters to succeed: 1) object to rez, 2) conveyance mode for the rezzed object
+    // to implement, 3) the chat channel to listen for and speak to new child on,
+    // 4) the destination name for where the child should go, 5) a count of the full
+    // set of known destinations, 6) the target where the jaunt should arrive at.
+string REPORT_CHILD_REZZED = "#reziam";
+    // requests that this class report to the root jaunter that a child has rezzed and
+    // is ready for service.  there are no required parameters.
+//hmmm: combine the above with the below!
+string REZOLATOR_CHILD_SUPPORT = "#rzsup";
+    // used by child jaunters to request that the rezolator handle things for them.
+    // the first parameter is the startup parameter handed to the control script.
+string REZOLATOR_CHILD_RETURNED = "#rezdon";
+    // used by the child jaunter to tell the rezolator that it has jumped to wherever it
+    // was supposed to and is ready to report to the parent, if needed.  the first parameter
+    // required for the rezolator is whether the jump was successful (1) or not (0), and
+    // the second parameter should be the last safe position that the jaunter was at when
+    // it was possibly closest to the target.
+//////////////
+// events generated by the library:
+string REZOLATOR_EVENT_REZZED_CHILD = "#donekd";
+    // an event generated for a previous rez child request.  this lets the caller know that
+    // the child has been created and told what to do.  the single parameter is where the
+    // jaunter has been rezzed.
+string REZOLATOR_EVENT_GOT_INSTRUCTIONS = "#rzsta";
+    // the root jaunter has given a child instructions on where to go.  this info includes
+    // the name of the destination, the pathway to get there, and the conveyance mode.
+string REZOLATOR_EVENT_RECON_FINISHED = "#rzcnfn";
+    // an event generated when the recon process has concluded.  this includes parms:
+    // number of good destinations.
+//
+//////////////
+
+// requires click action API...
+//////////////
+integer CHANGE_CLICK_ACTION_HUFFWARE_ID = 10024;
+    // a unique ID within the huffware system for this script.
+// the API only supports the service number; there are no commands to pass in the "msg"
+// parameter.  the id does accept a parameter, which is the type of click action to begin
+// using for this prim.
+//////////////
+
+// requires data cow library...
+//////////////
+// do not redefine these constants.
+integer DATA_COW_HUFFWARE_ID = 10017;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+//////////////
+//string RESET_LIST_COMMAND = "reset_L";  // flushes out the currently held list.
+string ADD_ITEM_COMMAND = "add_I";
+    // adds items to the list.  this is a list of pairs of name/value, where the name is
+    // how the item will be looked up from the list, and the value is the contents to be stored.
+//string REMOVE_ITEM_COMMAND = "rm_I";
+    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
+//string GET_ITEM_COMMAND = "get_I";
+    // retrieves the item's contents for a given name.  first parm is the name.  if there
+    // are other parameters, then they are taken as other items to return also.
+    // the return data will be pairs of <name, entry> for each of the names in the request.
+string TAGGED_GET_ITEM_COMMAND = "get_T";
+    // like get item, except the first parameter is an identifier that the caller wants to
+    // use to tag this request.  the other parameters are still taken as names.  the response
+    // will contain the tag as the first item, then the <name, entry> pairs that were found.
+//////////////
+
+// sets up the initial state, if this script has just started, or it
+// cleans up the state, if the script was already running.
+initialize_rezolator()
+{
+    if (DEBUGGING) log_it("start mem=" + (string)llGetFreeMemory());
+    global_rez_place = llGetPos();
+    heard_from_root = FALSE;  // we don't know root from adam yet.
+}
+
+// sets up the rezolator to be a child jaunter and report to a root jaunter.
+provide_child_support(integer startup_parm)
+{
+    serving_root = FALSE;
+    // we are serving as a special purpose jaunter object.
+    // set our method of jaunting based on the secret signal.
+    if (-(startup_parm - ONE_WAY_TRICKY_PARM) < MAXIMUM_PRIV_CHAN) {
+        conveyance_mode = ONE_WAY_TRIP;
+        private_chat_channel = startup_parm - ONE_WAY_TRICKY_PARM;
+        if (DEBUGGING) log_it("one way child: private chat on " + private_chat_channel);
+    } else if (-(startup_parm - RECONNAISSANCE_TRICKY_PARM) < MAXIMUM_PRIV_CHAN) {
+        conveyance_mode = RECONNAISSANCE_TRIP;
+        private_chat_channel = startup_parm - RECONNAISSANCE_TRICKY_PARM;
+        if (DEBUGGING) log_it("recon child: private chat on " + private_chat_channel);
+    }
+
+    if (private_id_from_listen) {
+        // toss old listening since we're working on a new deal now.
+        llListenRemove(private_id_from_listen);
+    }
+    // listen to chats on our special channel.
+    private_id_from_listen = llListen(private_chat_channel, "", NULL_KEY, "");
+    if (DEBUGGING) log_it("listening for cmds on chan " + (string)private_chat_channel);
+}
+
+// this handles the case where we need to send out another seeker drone.
+// true is returned if this function thinks things are doing well.
+integer advance_reconnaissance_position()
+{
+    if (!trying_hard_cases) {
+        list added_parms = [];
+        if (current_recon_index < 0) {
+            // this is a signalled condition.  we have just started chowing through
+            // the destinations to look at them.
+            current_recon_index = 0;
+        } else {
+            // a normal move to the next slot now.
+            current_recon_index++;
+        }
+        if (DEBUGGING)
+            log_it("total dests are " + destinations_total
+                + " and we're at indy " + current_recon_index);
+        if (current_recon_index <= destinations_total - 1) {
+            // try jumping to the next place.
+            if (DEBUGGING) log_it("next normal test, index " + (string)current_recon_index);
+            push_action_record(AQ_PREP_RECON_JAUNTER, added_parms);
+        } else {
+            // we've gone off the edge of our list in normal mode.
+            // now check those that are marked as failures.
+            trying_hard_cases = TRUE;
+            if (DEBUGGING) log_it("started trying hard cases, back to index 0");
+            // start over in processing the list.
+            current_recon_index = 0;
+            is_recon_pending = FALSE;
+            good_destinations_counted = 0;
+            ungenerated_good_destinations_counted = 0;
+            push_action_record(AQ_CHECK_HARD_CASE, added_parms);
+        }
+        llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+            wrap_parameters([OUR_COW_TAG, "#" + (string)current_recon_index]));
+        return TRUE;
+    }
+    if ((current_recon_index < destinations_total) && trying_hard_cases) {
+        // if the conditions are very right or very wrong, move to next place.
+        if ( (last_verification == VERIFY_SAFE) || (last_verification == VERIFY_UNSAFE_DECIDED) 
+            || (current_recon_index < 0) ) {
+            current_recon_index++;
+        }
+        if (DEBUGGING) log_it("next hard test at index " + (string)current_recon_index);
+        // make sure we're still in range.
+        if (current_recon_index < destinations_total) {
+            // we're running the hard cases now, so go to the next one of those.
+            list added_parms = [];
+            push_action_record(AQ_CHECK_HARD_CASE, added_parms);
+            llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+                wrap_parameters([OUR_COW_TAG, "#" + (string)current_recon_index]));
+            return TRUE;
+        }
+    }
+    
+    if (!done_reconnoiter) {
+        if (DEBUGGING) log_it("decided we're done with recon.");
+        // all have been checked.
+        done_reconnoiter = TRUE;
+        // let the root know how many were tasty healthy places.
+        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
+            REZOLATOR_EVENT_RECON_FINISHED,
+            (string)ungenerated_good_destinations_counted);
+    }
+    if (DEBUGGING) log_it("doing nothing else in advance.");
+    return FALSE;  // not good.
+}
+
+// considers the current state of affairs and schedules the next reasonable thing
+// that needs to be done to move the rezzing process along.
+take_the_next_appropriate_action()
+{
+    // see if the child setup process is still running.
+    if (child_needs_setup || is_recon_pending || (llGetListLength(action_queue) > 0) ) {
+        // we're still waiting on something.  make sure it hasn't timed out.
+        if (!check_for_child_timeout()) return;  // we still have time.
+        // saying this one failed, so we set it such that we are not waiting for kids
+        // or recons or the data cow right now.
+        snooze_counter = 0;
+        if (child_needs_setup) {
+            if (DEBUGGING) log_it("TNAP: child needs setup...");
+            child_needs_setup = FALSE;
+            if (conveyance_mode == ONE_WAY_TRIP) {
+//log_it("TNAP: telling root one way kid is hosed.");
+                // the startup of a child jaunter has failed.  let the root think we're
+                // doing okay so it can get on with its life.
+                llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
+                    REZOLATOR_EVENT_REZZED_CHILD, (string)global_rez_place);
+                return;
+            } else {
+//log_it("TNAP: recon fail for kid needs setup, fall through.");
+            }
+        } else if (is_recon_pending) {
+            // the current reconnaissance drone has crashed apparently.  deal with it.
+            if (DEBUGGING) log_it("TNAP: setting recon pend to false");
+            is_recon_pending = FALSE;
+            return;
+        } else if (llGetListLength(action_queue) > 0) {
+            // action_queue must be non-empty, or we wouldn't be here.
+            list action_rec = pop_action_record();  // what else can we do?
+            if (DEBUGGING) log_it("TNAP: time-out on action: " + (string)action_rec);
+            return;
+        }
+        // proceed to the next steps which are probably remedial.
+    }
+
+    if (DEBUGGING) log_it("TNAP: nothing pending, move things along...");
+
+    // nothing is pending right now.
+    if (conveyance_mode == ONE_WAY_TRIP) {
+        // this means we are done, since the only thing we do is start the kid up.
+        llSetTimerEvent(0.0);
+        return;
+    }
+
+    // if the recon advancement returns true, then we are all set for the next place.
+    if (advance_reconnaissance_position()) return;
+    
+    // if we got to here, then we need to do something about being past end of list...
+
+    if (done_reconnoiter) {
+        // all done with that, so we don't need the timer anymore.
+        llSetTimerEvent(0.0);  // stop coming here.
+        return;  // don't need to do any more.
+    }
+
+    if (trying_hard_cases) {
+        try_the_hard_cases();
+    }
+
+    if (DEBUGGING) log_it("fell completely through TNAP()");
+}
+
+// tries to crack the hard cases using added random jaunt destinations.
+try_the_hard_cases()
+{
+    if (DEBUGGING) log_it("hardcase performing recon re-attempt, name=" + global_destination_name);
+    if (is_prefix(global_destination_name, QUADRANT_TAG_NAME)) {
+//log_it("seeing that " + global_destination_name + " is a generated dest, ignoring.");
+        splice_destination_info(current_recon_index, "#" + (string)current_recon_index,
+            vector_chop(final_destination), VERIFY_UNSAFE_DECIDED);
+        advance_reconnaissance_position();
+        return;
+    }
+    // count that as a failure, since we're not still on our first run through the list.
+    recon_reattempts++;
+    if (recon_reattempts > MAXIMUM_RECON_ATTEMPTS) {
+        // we have totally failed to find a workable pathway.  we'll store the
+        // most simple form of the path back as the one to use.
+        log_it("total failure reaching " + (string)final_destination);
+        splice_destination_info(current_recon_index, "#" + (string)current_recon_index,
+            vector_chop(final_destination), VERIFY_UNSAFE_DECIDED);
+        recon_reattempts = 0;
+        advance_reconnaissance_position();
+        return;
+    }
+    
+    // start the process of finding a good random path.
+    if (!load_random_safe_path()) {
+        // can't get there from anywhere else, so try from here.
+        log_it("could not find a good random path!");
+        scramble_to_find_a_way([]);
+    }
+}
+
+// called to start a jaunter in the appropriate mode.
+rez_requested_child(string object_name, integer conv_mode,
+    integer chat_channel, string destination_name, integer all_dests_count,
+    string target_location)
+{
+    if (DEBUGGING)
+        log_it("rez req: " + object_name + " convey=" + (string)conveyance_mode + " chat=" + (string)chat_channel + " dest=" + destination_name + " fullcount=" + (string)all_dests_count + " targ=" + target_location);
+
+    if (private_id_from_listen) {
+        // toss old listening since we're working on a new deal now.
+        llListenRemove(private_id_from_listen);
+    }
+    // listen to chats on our special channel.
+    private_id_from_listen = llListen(chat_channel, "", NULL_KEY, "");
+    
+    // remember the info so we can tell our new child.
+    conveyance_mode = conv_mode;
+    global_destination_name = destination_name;
+    global_object_name = object_name;  // the object to rez from inventory.
+    private_chat_channel = chat_channel;
+    full_journey = llParseString2List(target_location, [VECTOR_SEPARATOR], []);
+    destinations_total = all_dests_count;
+    global_verifications = [];  // clear any old verifications.
+    integer indy;
+    for (indy = 0; indy < destinations_total; indy++)
+        global_verifications += [ VERIFY_UNTESTED ];
+
+    if (conveyance_mode == RECONNAISSANCE_TRIP) {
+        // we need to start reconnaissance mode.
+        current_recon_index = -1;  // a signal that we haven't started.
+        snooze_counter = 0;
+        is_recon_pending = FALSE;
+        done_reconnoiter = FALSE;
+
+//turned off currently.  doesn't seem to help much.
+if (FALSE) {
+        // experimental: add the quadrants of the sim as destinations.  if some of these
+        // are reachable, then they should help us out.
+        destinations_real = destinations_total;
+        integer x;
+        integer y;
+        for (x = 32; x <= 255; x += 64) {
+            for (y = 32; y <= 255; y += 64) {
+                vector calculated = <x, y, 0.0>;
+                float height = llGround(calculated - llGetPos());
+                calculated.z = height + 64;
+                add_destination(QUADRANT_TAG_NAME + (string)x + "," + (string)y, 
+                    (string)adjust_to_ground(<x, y, 0>, 64), VERIFY_UNTESTED);
+            }
+        }
+}
+
+        take_the_next_appropriate_action();
+    } else {
+        // create the jaunter object for a one way trip.
+        rez_a_jaunter(object_name, ONE_WAY_TRICKY_PARM + chat_channel, conveyance_mode);
+    }
+    llSetTimerEvent(TIMER_PERIOD);
+}
+
+// handles responses about our list coming back from the data cow.
+answer_to_the_cow(string msg, string id, list parms)
+{
+    string tag = llList2String(parms, 0);
+    if (tag != OUR_COW_TAG) return;  // was not for us.
+    parms = llDeleteSubList(parms, 0, 0);  // trim out the tag.
+    list action_record = pop_action_record();
+    integer actyo = extract_action_code(action_record);
+    // get the name out of the set first.
+    list split = llParseString2List(llList2String(parms, 1), [HUFFWARE_ITEM_SEPARATOR], []);
+    
+    if (actyo != AQ_ACQUIRE_BASE_PATH) {
+        // it's very important that when we're acquiring other targets' path components,
+        // we do not mistake that for our own state for the path we're trying to reach.
+        // thus we only record the answer for actions that are about our real target.
+        global_destination_name = llList2String(parms, 0);
+        last_verification = llList2Integer(split, 1);
+        full_journey = prechewed_destinations(llList2String(split, 0));
+        if (DEBUGGING)
+            log_it("just heard verif=" + (string)last_verification + " for " + global_destination_name);
+    }
+
+    if (actyo == AQ_ONEWAY_JAUNTER_VOYAGE) {
+//log_it("one way, saying on chan " + (string)private_chat_channel + " -- " + global_destination_name + " fullj=" + (string)full_journey);
+
+        child_needs_setup = FALSE;  // count off the one we just set up.
+
+        integer indy;  // i told you N times.
+        for (indy = 0; indy < MAX_CHAT_REPEAT; indy++) {
+            llSay(private_chat_channel, CHILD_CHAT_TEXT
+                + global_destination_name
+                + DB_SEPARATOR
+                + llDumpList2String(full_journey, VECTOR_SEPARATOR));
+            // pausing to let our words sink in.
+            llSleep(SLEEPY_TIME);
+        }
+
+        // tell the root jaunter that this kid has been issued.
+        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
+            REZOLATOR_EVENT_REZZED_CHILD, (string)global_rez_place );
+    } else if (actyo == AQ_PREP_RECON_JAUNTER) {
+        // we got info about a place to try.  record the last verif state locally.
+        if (DEBUGGING) log_it("info re destination: verif = " + last_verification);
+        splice_just_verification(current_recon_index, last_verification);
+        if ( (last_verification == VERIFY_UNTESTED)
+                || (trying_hard_cases && (last_verification == VERIFY_UNSAFE_SO_FAR) ) ) {
+            // this one is not tested yet or had problems.  try it now.
+//log_it("testing unchecked locale.");
+            is_recon_pending = TRUE;
+            // if the destination is claiming it's untested, we fix that now untrue statement.
+            if (last_verification == VERIFY_UNTESTED) {
+                splice_destination_info(current_recon_index, "#" + (string)current_recon_index,
+                    llDumpList2String(full_journey, VECTOR_SEPARATOR), VERIFY_UNSAFE_SO_FAR);
+            }
+            if (DEBUGGING)
+                log_it("rezzing jaunter for: name " + global_destination_name + " journ" + (string)full_journey);
+            rez_a_jaunter(global_object_name,
+                RECONNAISSANCE_TRICKY_PARM + private_chat_channel, RECONNAISSANCE_TRIP);
+        } else {
+            // this one doesn't need a recon.
+            is_recon_pending = FALSE;
+//log_it("skipping recon for verif " + (string)last_verification);
+            advance_reconnaissance_position();
+        }
+    } else if (actyo == AQ_CHECK_HARD_CASE) {
+        // we got an answer to our request for a new hard locale to try.
+        // remember the verification state locally.
+        splice_just_verification(current_recon_index, last_verification);
+
+        if ( (last_verification == VERIFY_UNTESTED) || (last_verification == VERIFY_UNSAFE_SO_FAR) ) {
+            // this one is not tested yet or had problems.  try it now.
+            if (DEBUGGING)
+                log_it("testing hard case locale at " + (string)current_recon_index
+                    + " name=" + global_destination_name);
+            final_destination = (vector)llList2String(full_journey, -1);
+            try_the_hard_cases();
+        } else {
+//log_it("check hard case--already safe or decidedly unsafe, skipping.");
+            if (last_verification == VERIFY_SAFE) {
+                good_destinations_counted++;
+                if (!is_prefix(global_destination_name, QUADRANT_TAG_NAME)) {
+                    ungenerated_good_destinations_counted++;
+                }
+            }
+            advance_reconnaissance_position();
+        }
+        take_the_next_appropriate_action();
+    } else if (actyo == AQ_ACQUIRE_BASE_PATH) {
+        // a response with a hopefully good destination arrived; base a path on that.
+        scramble_to_find_a_way(prechewed_destinations(llList2String(split, 0)));
+    }
+}
+
+// looks at the location "look_here" and finds the ground height as the z component
+// of the returned vector (where x and y are copied from "look_here").  if the
+// "height_add_in" is non-zero, it is added to the z component to adjust the ground
+// height by an offset.
+vector adjust_to_ground(vector look_here, float height_add_in)
+{
+    float height = llGround(look_here - llGetPos());
+    look_here.z = height + height_add_in;
+    return look_here;
+}
+
+// tries to come up with a random path that can reach a difficult place.
+scramble_to_find_a_way(list possible_helpful_path)
+{
+    // we were told this was a good pathway, so let's try it.
+    if (randomize_within_range(0.0, 1.0, FALSE) > 0.5) {
+        // if we feel like it, add some huge random vectors in.
+        integer indy;
+        integer how_many = (integer)randomize_within_range(1, 5, FALSE);
+//magic constant above.
+        vector rando = llGetPos();  // start with current place.
+        for (indy = 0; indy < how_many; indy++) {
+            // try to add a random completely other place in the sim.
+            vector other_rando = adjust_to_ground(random_vector(0.0, 256.0, FALSE), 64);
+            rando.z = other_rando.z;
+            // by only changing one axis at a time for x and y, we kind of slide around.
+            // this is considered more beneficial than just jumping randomly.
+            if (randomize_within_range(0.0, 1.0, FALSE) > 0.5) {
+                // this 50% modulates the x.
+                rando.x = other_rando.x;
+            } else {
+                // this other 50% modulates the y.
+                rando.y = other_rando.y;
+            }
+//log_it("scramble: wacky rando: " + vector_chop(rando));
+            possible_helpful_path += [ vector_chop(rando) ];
+        }
+    }
+    if (randomize_within_range(0.0, 1.0, FALSE) > 0.2) {
+        // maybe we also feel like adding a small amount to the final destination,
+        // trying for a hook shot, most of the time.
+//log_it("scramble: addition relative to final destination.");
+        vector rando = adjust_to_ground(final_destination + random_vector(0.0, 8.0, TRUE), 64);
+//magic constant above.
+        possible_helpful_path += [ vector_chop(rando) ];
+    }
+    if ( (final_destination.z < 1000.0) && (randomize_within_range(0.0, 1.0, FALSE) > 0.05) ) {
+//hmmm: is this redundant now?
+        // we very often add a vertical component so as to swoop down on the destination
+        // and hopefully avoid ground fault conditions.
+        possible_helpful_path += [ vector_chop(<final_destination.x, final_destination.y,
+            final_destination.z + 64>) ];
+//magic constant above.
+    }
+    // now finally we add in the real place where we're going.
+    possible_helpful_path += [ vector_chop(final_destination) ];
+    // prepare our state for the new attempt.
+    is_recon_pending = TRUE;
+    snooze_counter = 0;
+    full_journey = possible_helpful_path;
+//log_it("scramble: final guess=" + (string)full_journey);
+    // rez for this nutty test path.
+    rez_a_jaunter(global_object_name,
+        RECONNAISSANCE_TRICKY_PARM + private_chat_channel, RECONNAISSANCE_TRIP);
+}
+
+// this function returns TRUE if we are close enough to the "destination".
+integer close_enough(vector destination)
+{
+    float PROXIMITY_REQUIRED = 0.1;
+        // how close we must be to the target location to call it done.
+        // matches current jaunting library proximity.
+    return (llVecDist(llGetPos(), destination) <= PROXIMITY_REQUIRED);
+}
+
+// records a verification state locally so we can make decisions during testing.
+splice_just_verification(integer index, integer verif_state)
+{
+    if ( (index < 0) || (index >= destinations_total) ) return;  // can't do it.
+    global_verifications = chop_list(global_verifications, 0, index - 1)
+        + [ verif_state ]
+        + chop_list(global_verifications, index + 1, destinations_total - 1);
+}
+
+// replaces an existing entry at the "index" if known (otherwise this should be negative)
+// for the location named "dest_name" if known (otherwise should be a restatement of the
+// numerical index with '#' in front).
+splice_destination_info(integer index, string dest_name, string pathway, integer verif)
+{
+//log_it("splicedest: " + (string)index + " name=" + dest_name + " verif=" + (string)verif + " path=" + pathway);
+    splice_just_verification(index, verif);
+    string new_entry = wrap_item_list([pathway, verif]);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, ADD_ITEM_COMMAND,
+        wrap_parameters([dest_name, new_entry]));
+}
+
+string verification_name(integer enumtype)
+{
+    if (enumtype == VERIFY_SAFE) return "ok";
+    else if (enumtype == VERIFY_UNSAFE_SO_FAR) return "uhh";
+    else if (enumtype == VERIFY_UNSAFE_DECIDED) return "far";
+    // catch-all, including untested.
+    return "?";
+}
+
+// returns true if the slackness counter awaiting things has elapsed.
+integer check_for_child_timeout()
+{
+    if (snooze_counter++ > MAXIMUM_SNOOZES) {
+        // go back to the main state.  we took too long.
+//        log_it("timed out!");
+        llUnSit(llAvatarOnSitTarget());  // don't hang onto the avatar for this error.
+        return TRUE;
+    }
+    return FALSE;
+}
+
+//////////////
+
+// action queue for postponed activities.  the first field held in a list item here
+// is an integer action code.  the format of the remaining parameters is up to the
+// caller, and they can be used as the final parameters for when the queued action
+// gets handled.
+list action_queue;
+
+// looks at the action code at the head of the queue without removing the action.
+integer peek_action_code()
+{
+    list fields = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
+    return extract_action_code(fields);
+}
+
+// extracts the action code from a retrieved list.
+integer extract_action_code(list to_parse) { return llList2Integer(to_parse, 0); }
+
+// removes the current head of the action queue and returns it.
+list pop_action_record()
+{
+    list top_action = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
+    action_queue = llDeleteSubList(action_queue, 0, 0);
+    return top_action;
+}
+
+// adds a new action to the end of the action queue.
+push_action_record(integer action, list added_parms)
+{
+    snooze_counter = 0;  // reset back for new action.
+    action_queue += [ wrap_parameters([action] + added_parms) ];
+}
+
+//////////////
+
+// processes link messages received from support libraries.
+handle_link_message(integer which, integer num, string msg, string id)
+{
+    // maybe it's a piece of data from the data cow.
+    if (num == DATA_COW_HUFFWARE_ID + REPLY_DISTANCE) {
+        // unpack the parameters we were given.
+        list parms_x = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        answer_to_the_cow(msg, id, parms_x);
+        return;
+    }
+    
+    if (num != JAUNT_REZOLATOR_HUFFWARE_ID) return;  // not interesting.
+    if (DEBUGGING) log_it("linkmsg: msg " + msg + " id " + id);
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    if (msg == REZ_CHILD_NOW) {
+        serving_root = TRUE;
+        snooze_counter = 0;  // reset counter.
+        if (llGetListLength(parms) < REZ_KID_FIELDS_NEEDED) {
+//                log_it("insufficient parameters for rezzing child.");
+            return;
+        }
+        rez_requested_child(llList2String(parms, 0), llList2Integer(parms, 1),
+            llList2Integer(parms, 2), llList2String(parms, 3),
+            llList2Integer(parms, 4), llList2String(parms, 5));
+    } else if (msg == REPORT_CHILD_REZZED) {
+        report_to_root();
+    } else if (msg == RESET_REZOLATOR) {
+        llResetScript();
+    } else if (msg == REZOLATOR_CHILD_SUPPORT) {
+        provide_child_support(llList2Integer(parms, 0));
+    } else if (msg == REZOLATOR_CHILD_RETURNED) {
+        if (conveyance_mode == RECONNAISSANCE_TRIP) {
+            // unpack the success value from jaunter's check.
+            integer succeeded_recon = llList2Integer(parms, 0);
+            // report on our success.
+            list report_loc = full_journey;
+            if (!succeeded_recon) {
+                // we did at least get to somewhere, even if not to target.
+                report_loc = llParseString2List(llList2String(parms, 1),
+                    [VECTOR_SEPARATOR], []);
+            }
+            llWhisper(private_chat_channel, CHILD_CHAT_TEXT + RETURN_WORD
+                + (string)succeeded_recon + DB_SEPARATOR
+                + global_destination_name
+                + DB_SEPARATOR
+                + llDumpList2String(report_loc, VECTOR_SEPARATOR));
+//log_it("child reporting success=" + (string)succeeded_recon + " for " + global_destination_name + " via " + llDumpList2String(report_loc, VECTOR_SEPARATOR) );
+            // shuffle off...
+//log_it("now dying at posn " + (string)llGetPos());
+            llDie();  // oh crud, we're toast.
+        } else {
+            // one way trip??
+            if (!succeeded_recon) log_it("too far away; path okay?");
+        }
+    }
+}
+
+// makes our click action change to the type requested, and sends the request
+// out to all our sub-prims also.
+set_click_action(integer action)
+{
+    llSetClickAction(action);
+    // secret message to other prims to change click action.
+    llMessageLinked(LINK_SET, CHANGE_CLICK_ACTION_HUFFWARE_ID, "", (string)action);
+}
+
+// tries to find a known safe locale that's close to the target.  if there are any
+// that are close, then we will not add this location.  otherwise, we do add it,
+// if the list is not already too large.
+add_if_no_close_match(string pathway)
+{
+    // make sure there's enough room to bother checking.
+    if (llGetListLength(safe_locales_seen) >= MAXIMUM_SAFE_LOCATIONS) return;
+    list dests = llParseString2List(pathway, [VECTOR_SEPARATOR], []);
+    vector final_locn = (vector)llList2String(dests, -1);
+    // set the z component to zero for this comparison, which is only about x,y position.
+    // since we then add this trimmed vector, we don't need to worry about the z component
+    // for the items already in the list.
+    final_locn.z = 0;
+    integer i;
+    for (i = 0; i < llGetListLength(safe_locales_seen); i++) {
+        vector curr = (vector)llList2String(safe_locales_seen, i);
+        if (llVecDist(curr, final_locn) < MINIMUM_DISTANCE_FOR_EXTRAS) {
+//log_it("dest too close: dist = " + (string)llVecDist(curr, final_locn));
+            return;
+        }
+    }
+    if (DEBUGGING) log_it("dest far enough to add: " + pathway);
+    // no known locale is close, so we'll add this one.
+    safe_locales_seen += [ final_locn ];
+    good_destinations_counted++;
+    add_destination(QUADRANT_TAG_NAME + "pt#" + (string)(partial_path_count++),
+        pathway, VERIFY_SAFE);
+}
+
+// process what we hear in open chat and on our special channels.
+// this function should always return FALSE unless it's been given enough info
+// to enter a new state, in which case it should return true.
+listen_to_voices(integer channel, string name, key id, string message)
+{
+    // check to see if the text is right.
+    if (DEBUGGING)
+        log_it("heard: " + message + " from " + name);
+    if (!is_prefix(message, CHILD_CHAT_TEXT)) return;  // not right.
+    message = llDeleteSubString(message, 0, llStringLength(CHILD_CHAT_TEXT) - 1);
+    // maybe this is a startup request.
+    if (is_prefix(message, READY_TEXT) && serving_root) {
+        // yes, this is a request for a destination.  we are going to fill the rezzed object
+        // now, so figure out what type of jaunter needs info.  formerly fill_rezzed_object.
+        integer is_recon = (integer)llGetSubString(message, -1, -1);
+        if (done_reconnoiter && is_recon) return;  // we already did all that.
+        if (is_recon) {
+            // a recon jaunter needs its instructions.
+            if (DEBUGGING)
+                log_it("telling recon kid: name " + global_destination_name + " journ=" + (string)full_journey);
+            is_recon_pending = TRUE;
+            integer indy;  // i told you N times.
+            for (indy = 0; indy < MAX_CHAT_REPEAT; indy++) {
+                llSay(private_chat_channel, CHILD_CHAT_TEXT
+                    + global_destination_name
+                    + DB_SEPARATOR
+                    + llDumpList2String(full_journey, VECTOR_SEPARATOR));
+                // snooze to make sure we pause a little between mouthings.
+                llSleep(SLEEPY_TIME);
+            }
+
+            snooze_counter = 0;  // starting over.
+            child_needs_setup = FALSE;  // count off the one we just set up.
+        } else {
+            if (DEBUGGING)
+                log_it("into code for one way jaunter");
+            // simple one way jaunter needs fillin'.
+            list added_parms = [];
+            push_action_record(AQ_ONEWAY_JAUNTER_VOYAGE, added_parms);
+            llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+                wrap_parameters([OUR_COW_TAG, global_destination_name]));
+        }
+        return;
+    }
+
+    if (DEBUGGING) log_it("into kid side of rezolator...");
+
+    if (!serving_root) {
+        if ( (conveyance_mode == RECONNAISSANCE_TRIP) || (conveyance_mode == ONE_WAY_TRIP) ) {
+            if (heard_from_root) return;  // we already did this bit.
+            // this jaunter is destined for short-lived work, but now at least has a goal.
+            // we just pass along the parameters that were told to us from the root jaunter.
+            list parms = llParseString2List(message, [DB_SEPARATOR], []);
+            global_destination_name = llList2String(parms, 0);
+            full_journey = llParseString2List(llList2String(parms, 1), [VECTOR_SEPARATOR], []);
+            final_destination = (vector)llList2String(full_journey, -1);
+            parms += [ conveyance_mode ];
+    
+            if (conveyance_mode == ONE_WAY_TRIP) {
+                // set the click action properly.
+                if (outside_of_sim(final_destination)) set_click_action(CLICK_ACTION_TOUCH);
+                else set_click_action(CLICK_ACTION_SIT);
+            }
+    
+            if (DEBUGGING) log_it("kid heard go to: " + global_destination_name + " via " + (string)full_journey);
+            llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
+                REZOLATOR_EVENT_GOT_INSTRUCTIONS, wrap_parameters(parms));
+            // make sure we cancel the listening so we don't hear directions that aren't for us.
+            llListenRemove(private_id_from_listen);
+            heard_from_root = TRUE;
+            return;  // only leave for recon.
+        }
+    } else {
+        // this jaunter's role should be a root jaunter, and we have a reply about a recon mission.
+        is_recon_pending = FALSE;  // we got an acceptable answer.
+        list parms = llParseString2List(llDeleteSubString
+            (message, 0, llStringLength(RETURN_WORD) - 1), [DB_SEPARATOR], []);
+        integer success = llList2Integer(parms, 0);
+        string dest_name = llList2String(parms, 1);
+        string pathway = llList2String(parms, 2);
+//log_it("|||| recon reply: " + dest_name + " good=" + (string)success + " path=" + pathway);
+        if (success) {
+            // record this as a safe pathway.
+            last_verification = VERIFY_SAFE;
+            good_destinations_counted++;
+        } else {
+            // a failure is being reported.  record this as a bad pathway.
+            last_verification = VERIFY_UNSAFE_SO_FAR;
+            // however, the jaunter should have told us where it did get to.  record that whole
+            // thing if it seems like a good distance from our other known good places.
+            if (DEBUGGING) log_it("failed path did get to: " + pathway);
+            add_if_no_close_match(pathway);
+
+        }
+        // only save this info if we're not working on recons.
+        if (!trying_hard_cases || success) {
+            // fix name for tough destination's real one.
+            if (trying_hard_cases) {
+                dest_name = "#" + (string)current_recon_index;
+            }
+            splice_destination_info(current_recon_index, dest_name,
+                llDumpList2String(full_journey,
+                    ///llList2List(full_journey, 1, -1), 
+                VECTOR_SEPARATOR),
+                last_verification);
+        }
+        take_the_next_appropriate_action();
+    }
+}
+
+// processes a destination set to handle special cases, like for offset jaunting.
+list prechewed_destinations(string dests)
+{
+
+//hmmm: document this!  as in, we support the offset format.
+
+    // look for our special start character for offsets.
+    if (is_prefix(dests, "o"))
+        // if this is an offset version, then chop whatever word they used starting with 'o'
+        // and compute the destination based on current position.
+        return [ (vector)llDeleteSubString(dests, 0, find_substring(dests, "<") - 1) + llGetPos() ];
+    else
+        // normal jaunt to absolute coordinates.
+        return llParseString2List(dests, [VECTOR_SEPARATOR], []);
+}
+
+// creates a jaunter object given which inventory item and the startup parm.
+rez_a_jaunter(string object_name, integer rez_parm, integer conveyance_mode)
+{
+    // the minimum and maximum distances for placing the auto-rezzed jaunter object.
+    integer MIN_REZ_DISTANCE = 1;
+    integer MAX_REZ_DISTANCE = 3;
+    vector RECON_ROTATION = <270.0, 0.0, 0.0>;
+        // what angle we use when planting the recon jaunter.
+        // this is tightly coupled to our particular object.
+    vector point_at_jaunter;
+    if (conveyance_mode == RECONNAISSANCE_TRIP) {
+        // we just use our specified rotation.
+        point_at_jaunter = RECON_ROTATION * DEG_TO_RAD;
+        // start at where the jaunter will be when it tries the same path.
+        global_rez_place  = llGetPos();
+    } else {
+        // we randomize the location to avoid people having the objects
+        // in a big pile on top of each other.
+        global_rez_place  = llGetPos()
+            + <randomize_within_range(MIN_REZ_DISTANCE, MAX_REZ_DISTANCE, TRUE),
+                randomize_within_range(MIN_REZ_DISTANCE, MAX_REZ_DISTANCE, TRUE),
+                0.4>;  // pop it up a bit.
+        // aim the temporary ride at the root jaunter.
+        vector aim_back = llGetPos() - global_rez_place;
+        float z_rot = llAtan2(aim_back.y, aim_back.x);
+        // calculate the vector for rotation given the z rotation.
+        point_at_jaunter = <0.0, 0.0, z_rot>;
+    }    
+    llRezObject(object_name, global_rez_place,
+        ZERO_VECTOR, llEuler2Rot(point_at_jaunter), rez_parm);
+    if (conveyance_mode != RECONNAISSANCE_TRIP) {
+        // this model only jaunts to where it gave out the object.  that
+        // should hopefully always work.  but at least if it can't get back,
+        // it's really close by.
+        full_journey = [ vector_chop(llGetPos()), vector_chop(global_rez_place) ];
+    }
+    child_needs_setup = TRUE;  // we aren't ready to go even if jaunt is done.
+    snooze_counter = 0;  // amnesty on the timer.
+}
+
+// finds a pathway that's already in our list and that we think is safe.
+integer load_random_safe_path()
+{
+    integer indy;
+    integer goodunz = good_destinations_counted;
+
+    // now that we know how many are safe, we can pick a good destination.
+    integer randola = llRound(randomize_within_range(0, goodunz - 1, FALSE));
+    integer safe_indy = -1;  // tracks which safe item we're at.
+    for (indy = 0; indy < llGetListLength(global_verifications); indy++) {
+        // scoot across the list to find the Nth safe one.
+        if (llList2Integer(global_verifications, indy) == VERIFY_SAFE) {
+            if (safe_indy == randola) {
+//log_it("like path at " + (string)safe_indy);
+                // we're at the Nth safe item, so this is our random choice.
+                list added_parms = [];
+                push_action_record(AQ_ACQUIRE_BASE_PATH, added_parms);
+                llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+                    wrap_parameters([OUR_COW_TAG, "#" + (string)safe_indy]));
+                return TRUE;
+            }
+            // increment to the next position, since we've seen this one.
+            safe_indy++;
+        }
+    }
+//log_it("found no good path to use");
+    return FALSE;
+}
+
+// processes the timer events during an ongoing rezzing process.
+handle_timer()
+{
+    // this is the root's timer process, which is implemented in great detail
+    // in the function below.
+    if (serving_root) take_the_next_appropriate_action();
+}
+
+// file a report with the root jaunter that the child has been created and is
+// ready for service.
+report_to_root()
+{
+    // tell the root jaunter know that we're ready to be packed for our trip.
+    llSay(private_chat_channel, CHILD_CHAT_TEXT + READY_TEXT
+        + (string)(conveyance_mode == RECONNAISSANCE_TRIP));
+}
+
+// plops a new destination on the end of the lists.
+add_destination(string name, string path, integer verif)
+{
+//log_it("adding " + name + " with path " + path + " and verif=" + (string)verif);
+    global_verifications += [ verif ];
+    // send our new information to the data cow.  we store the information encoded as
+    // two separated items, where the first element is the destination and the second
+    // is the verification state.
+    string new_entry = wrap_item_list([path, verif]);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, ADD_ITEM_COMMAND,
+        wrap_parameters([name, new_entry]));
+    destinations_total++;  // we just added another destination.
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
+integer valid_sim_value(float to_check)
+{
+    if (to_check < 0.0) return FALSE;
+    if (to_check >= 257.0) return FALSE;
+    return TRUE;
+}
+
+// returns TRUE if the "to_check" vector is a location outside of the current sim.
+integer outside_of_sim(vector to_check)
+{
+    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
+}
+
+// returns text for a floating point number, but includes only
+// two digits after the decimal point.
+string float_chop(float to_show)
+{
+    integer mant = llAbs(llRound(to_show * 100.0) / 100);
+    string neg_sign;
+    if (to_show < 0.0) neg_sign = "-";
+    string dec_s = (string)((llRound(to_show * 100.0) - mant * 100) / 100.0);
+    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
+    // strip off all trailing zeros.
+    while (llGetSubString(dec_s, -1, -1) == "0")
+        dec_s = llDeleteSubString(dec_s, -1, -1);
+    string to_return = neg_sign + (string)mant;
+    if (llStringLength(dec_s)) to_return += "." + dec_s;
+    return to_return;
+}
+
+// returns a prettier form for vector text, with chopped floats.
+string vector_chop(vector to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ">";
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{
+    string full_lower = llToLower(full_string);
+    return llSubStringIndex(full_lower, pattern);
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); initialize_rezolator(); }
+
+    on_rez(integer startup) { llResetScript(); }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+
+    listen(integer channel, string name, key id, string message)
+    { listen_to_voices(channel, name, id, message); }
+
+    timer() { handle_timer(); }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunt_rezolator_v22.3.txt b/huffware/huffotronic_jaunter_updater_v5.1/jaunt_rezolator_v22.3.txt
deleted file mode 100755 (executable)
index f7f7481..0000000
+++ /dev/null
@@ -1,1278 +0,0 @@
-
-// huffware script: jaunt rezolator, by fred huffhines.
-//
-// this script supports the jaunt wik rez script by dealing with the rezzed objects.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants that can be changed to good effect.
-
-integer DEBUGGING = FALSE;  // set this to true for noisier run times.
-
-// important constants used internally...  these should not be changed willy nilly.
-
-// begin jaunt base API:
-
-// the following constants define how the script should behave (i.e., its conveyance mode).
-// TWO_WAY_TRIP: the script jaunts using the current target vectors to get somewhere
-//   and then takes the same pathway back, but in reverse order.
-// AUTOREZ_JAUNTER: the script rezzes the first regular object in its inventory next to
-//   the root telehub.  that object is loaded with the destination notecard and this script.
-//   the rezzed object can then be used for the next few minutes to jaunt to the selected
-//   destination.  the temporary object will use the ONE_WAY_TRIP mode.
-// ONE_WAY_TRIP: the object containing this script will take the user to a particular
-//   destination, but the object does not survive the trip.  it self-destructs after
-//   reaching the destination.  this mode is used in conjunction with the AUTOREZ_JAUNTER
-//   mode and should generally never be used on its own.
-// RECONNAISSANCE_TRIP: a survey run to test out a particular path to get to a
-//   destination.
-integer TWO_WAY_TRIP = 1;
-integer AUTOREZ_JAUNTER = 2;
-integer ONE_WAY_TRIP = 3;
-integer RECONNAISSANCE_TRIP = 4;
-
-// indicates a reconnaissance command when found as a prefix on chat text
-// on our official recon channel.
-string CHILD_CHAT_TEXT = "#rcn";
-string READY_TEXT = "-y";  // lets us know that a jaunter is ready to be filled.
-string RETURN_WORD = "-b";  // used to signal a returning recong jaunter.
-
-// values used to represent different stages of verification.
-integer VERIFY_UNTESTED = -3;  // don't know destinations tate yet.
-integer VERIFY_SAFE = -4;  // the destination last tested safe.
-integer VERIFY_UNSAFE_SO_FAR = -5;  // this cannot be done with simple jaunt.
-integer VERIFY_UNSAFE_DECIDED = -6;  // this means the destination seems intractable.
-
-integer ONE_WAY_TRICKY_PARM = -100000;
-    // used to signal to the one way jaunter that it's taking a single pathway.
-integer RECONNAISSANCE_TRICKY_PARM = -200000;
-    // on_rez parm indicates that this will be a recon trip to check out a path.
-integer MAXIMUM_PRIV_CHAN = 90000;
-    // the largest amount we will ever subtract from the tricky parms in order to
-    // tell the sub-jaunter which channel to listen on.
-
-string VECTOR_SEPARATOR = "|";
-    // how we separate components of vectors from each other.
-string DB_SEPARATOR = "``";  // separating items in lists.
-
-// end of jaunt base API.
-
-integer REZ_KID_FIELDS_NEEDED = 6;  // the rez kid API method needs this many parms.
-
-integer MAXIMUM_RECON_ATTEMPTS = 7;
-    // maximum tries to find a path for the hard cases (after first simple jaunt fails).
-
-float TIMER_PERIOD = 1.0;  // we run a pretty slow timer to check on destinations.
-
-integer MAXIMUM_SNOOZES = 20;  // how long we let a pending action go before declaring it failed.
-
-string OUR_COW_TAG = "l_jrzltr_dc";
-    // a hopefully unique id for this script to talk to the data cow with.
-
-// the actions that can be held in the action queue.
-integer AQ_ONEWAY_JAUNTER_VOYAGE = 40;  // information will be used for one-way jaunter.
-integer AQ_PREP_RECON_JAUNTER = 41;  // info for the reconnaissance jaunter to go check out.
-integer AQ_CHECK_HARD_CASE = 42;  // working on hard cases to get to destination somehow.
-integer AQ_ACQUIRE_BASE_PATH = 43;  // we are grabbing a random path that we think is healthy.
-
-string QUADRANT_TAG_NAME = "q:";  // a piece of text we put in front of generated destinations.
-
-integer MAXIMUM_SAFE_LOCATIONS = 28;  // we'll track this many extra locations.
-float MINIMUM_DISTANCE_FOR_EXTRAS = 10.0;  // how far a new locale must be to add.
-
-integer MAX_CHAT_REPEAT = 3;  // give instructions N times in case things are slow.
-float SLEEPY_TIME = 0.02;  // how long to snooze between chats.
-
-//////////////
-
-// global variables.
-
-list global_verifications;  // we gradually acquire knowledge of the health of the destinations.
-string global_object_name;  // the object to rez from inventory.
-string global_destination_name;  // the name of the place where the jaunter should go.
-vector global_rez_place;  // starting location for the rezzed jaunter.
-integer conveyance_mode;  // how the rezzed jaunter should process its destination.
-
-integer private_id_from_listen;  // set when we listen to our private channel.
-integer private_chat_channel;  // where sub-jaunters communicate with root.
-
-integer serving_root;  // if this is true, it means we are serving a root jaunter.
-
-integer destinations_total;  // how many destinations are known in total?  we compute this.
-integer destinations_real;  // how many are user-configured destinations?
-
-integer snooze_counter;  // how many times have we slept during a process?
-
-integer heard_from_root;  // true if the root jaunter has told us (a child jaunter) where to go.
-
-// recon variables...
-integer is_recon_pending;  // are we awaiting a reconnaissance?
-integer trying_hard_cases;  // are we already working on the tough ones?
-integer current_recon_index;  // where is the recon jaunter testing.
-integer recon_reattempts;  // how many tries did we take?
-integer done_reconnoiter;  // is recon process finished?
-integer succeeded_recon;  // set to true if close enough.
-integer good_destinations_counted;  // a tally of how many destinations looked healthy.
-integer ungenerated_good_destinations_counted;  // counts only user selected good dests.
-vector final_destination;  // where the recon process is really headed.
-integer partial_path_count;  // the counter for partial path replies.
-list safe_locales_seen;  // locations that we have a safe route to, as reported by recons.
-
-// jaunt trip variables...
-list full_journey;  // the full pathway we expect to jaunt on.
-integer last_verification;  // the last state we heard.
-
-// root jaunter variables...
-integer child_needs_setup;
-    // true when a child has been rezzed and still needs to be filled with the script.
-
-// the API for this library script to be used in other scripts.
-//////////////
-// do not redefine these constants.
-integer JAUNT_REZOLATOR_HUFFWARE_ID = 10025;
-    // the unique id within the huffware system for this script's commands.
-    // it's used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-// commands available from the library:
-string RESET_REZOLATOR = "#reset";
-    // tells the script to stop any previous efforts to rez children.
-string REZ_CHILD_NOW = "#rezkd#";
-    // requests this script to create a new child object.  this requires several
-    // parameters to succeed: 1) object to rez, 2) conveyance mode for the rezzed object
-    // to implement, 3) the chat channel to listen for and speak to new child on,
-    // 4) the destination name for where the child should go, 5) a count of the full
-    // set of known destinations, 6) the target where the jaunt should arrive at.
-string REPORT_CHILD_REZZED = "#reziam";
-    // requests that this class report to the root jaunter that a child has rezzed and
-    // is ready for service.  there are no required parameters.
-//hmmm: combine the above with the below!
-string REZOLATOR_CHILD_SUPPORT = "#rzsup";
-    // used by child jaunters to request that the rezolator handle things for them.
-    // the first parameter is the startup parameter handed to the control script.
-string REZOLATOR_CHILD_RETURNED = "#rezdon";
-    // used by the child jaunter to tell the rezolator that it has jumped to wherever it
-    // was supposed to and is ready to report to the parent, if needed.  the first parameter
-    // required for the rezolator is whether the jump was successful (1) or not (0), and
-    // the second parameter should be the last safe position that the jaunter was at when
-    // it was possibly closest to the target.
-//////////////
-// events generated by the library:
-string REZOLATOR_EVENT_REZZED_CHILD = "#donekd";
-    // an event generated for a previous rez child request.  this lets the caller know that
-    // the child has been created and told what to do.  the single parameter is where the
-    // jaunter has been rezzed.
-string REZOLATOR_EVENT_GOT_INSTRUCTIONS = "#rzsta";
-    // the root jaunter has given a child instructions on where to go.  this info includes
-    // the name of the destination, the pathway to get there, and the conveyance mode.
-string REZOLATOR_EVENT_RECON_FINISHED = "#rzcnfn";
-    // an event generated when the recon process has concluded.  this includes parms:
-    // number of good destinations.
-//
-//////////////
-
-// requires click action API...
-//////////////
-integer CHANGE_CLICK_ACTION_HUFFWARE_ID = 10024;
-    // a unique ID within the huffware system for this script.
-// the API only supports the service number; there are no commands to pass in the "msg"
-// parameter.  the id does accept a parameter, which is the type of click action to begin
-// using for this prim.
-//////////////
-
-// requires data cow library...
-//////////////
-// do not redefine these constants.
-integer DATA_COW_HUFFWARE_ID = 10017;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-//////////////
-//string RESET_LIST_COMMAND = "reset_L";  // flushes out the currently held list.
-string ADD_ITEM_COMMAND = "add_I";
-    // adds items to the list.  this is a list of pairs of name/value, where the name is
-    // how the item will be looked up from the list, and the value is the contents to be stored.
-//string REMOVE_ITEM_COMMAND = "rm_I";
-    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
-//string GET_ITEM_COMMAND = "get_I";
-    // retrieves the item's contents for a given name.  first parm is the name.  if there
-    // are other parameters, then they are taken as other items to return also.
-    // the return data will be pairs of <name, entry> for each of the names in the request.
-string TAGGED_GET_ITEM_COMMAND = "get_T";
-    // like get item, except the first parameter is an identifier that the caller wants to
-    // use to tag this request.  the other parameters are still taken as names.  the response
-    // will contain the tag as the first item, then the <name, entry> pairs that were found.
-//////////////
-
-// sets up the initial state, if this script has just started, or it
-// cleans up the state, if the script was already running.
-initialize_rezolator()
-{
-    if (DEBUGGING) log_it("start mem=" + (string)llGetFreeMemory());
-    global_rez_place = llGetPos();
-    heard_from_root = FALSE;  // we don't know root from adam yet.
-}
-
-// sets up the rezolator to be a child jaunter and report to a root jaunter.
-provide_child_support(integer startup_parm)
-{
-    serving_root = FALSE;
-    // we are serving as a special purpose jaunter object.
-    // set our method of jaunting based on the secret signal.
-    if (-(startup_parm - ONE_WAY_TRICKY_PARM) < MAXIMUM_PRIV_CHAN) {
-        conveyance_mode = ONE_WAY_TRIP;
-        private_chat_channel = startup_parm - ONE_WAY_TRICKY_PARM;
-        if (DEBUGGING) log_it("one way child: private chat on " + private_chat_channel);
-    } else if (-(startup_parm - RECONNAISSANCE_TRICKY_PARM) < MAXIMUM_PRIV_CHAN) {
-        conveyance_mode = RECONNAISSANCE_TRIP;
-        private_chat_channel = startup_parm - RECONNAISSANCE_TRICKY_PARM;
-        if (DEBUGGING) log_it("recon child: private chat on " + private_chat_channel);
-    }
-
-    if (private_id_from_listen) {
-        // toss old listening since we're working on a new deal now.
-        llListenRemove(private_id_from_listen);
-    }
-    // listen to chats on our special channel.
-    private_id_from_listen = llListen(private_chat_channel, "", NULL_KEY, "");
-    if (DEBUGGING) log_it("listening for cmds on chan " + (string)private_chat_channel);
-}
-
-// this handles the case where we need to send out another seeker drone.
-// true is returned if this function thinks things are doing well.
-integer advance_reconnaissance_position()
-{
-    if (!trying_hard_cases) {
-        list added_parms = [];
-        if (current_recon_index < 0) {
-            // this is a signalled condition.  we have just started chowing through
-            // the destinations to look at them.
-            current_recon_index = 0;
-        } else {
-            // a normal move to the next slot now.
-            current_recon_index++;
-        }
-        if (DEBUGGING)
-            log_it("total dests are " + destinations_total
-                + " and we're at indy " + current_recon_index);
-        if (current_recon_index <= destinations_total - 1) {
-            // try jumping to the next place.
-            if (DEBUGGING) log_it("next normal test, index " + (string)current_recon_index);
-            push_action_record(AQ_PREP_RECON_JAUNTER, added_parms);
-        } else {
-            // we've gone off the edge of our list in normal mode.
-            // now check those that are marked as failures.
-            trying_hard_cases = TRUE;
-            if (DEBUGGING) log_it("started trying hard cases, back to index 0");
-            // start over in processing the list.
-            current_recon_index = 0;
-            is_recon_pending = FALSE;
-            good_destinations_counted = 0;
-            ungenerated_good_destinations_counted = 0;
-            push_action_record(AQ_CHECK_HARD_CASE, added_parms);
-        }
-        llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-            wrap_parameters([OUR_COW_TAG, "#" + (string)current_recon_index]));
-        return TRUE;
-    }
-    if ((current_recon_index < destinations_total) && trying_hard_cases) {
-        // if the conditions are very right or very wrong, move to next place.
-        if ( (last_verification == VERIFY_SAFE) || (last_verification == VERIFY_UNSAFE_DECIDED) 
-            || (current_recon_index < 0) ) {
-            current_recon_index++;
-        }
-        if (DEBUGGING) log_it("next hard test at index " + (string)current_recon_index);
-        // make sure we're still in range.
-        if (current_recon_index < destinations_total) {
-            // we're running the hard cases now, so go to the next one of those.
-            list added_parms = [];
-            push_action_record(AQ_CHECK_HARD_CASE, added_parms);
-            llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-                wrap_parameters([OUR_COW_TAG, "#" + (string)current_recon_index]));
-            return TRUE;
-        }
-    }
-    
-    if (!done_reconnoiter) {
-        if (DEBUGGING) log_it("decided we're done with recon.");
-        // all have been checked.
-        done_reconnoiter = TRUE;
-        // let the root know how many were tasty healthy places.
-        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
-            REZOLATOR_EVENT_RECON_FINISHED,
-            (string)ungenerated_good_destinations_counted);
-    }
-    if (DEBUGGING) log_it("doing nothing else in advance.");
-    return FALSE;  // not good.
-}
-
-// considers the current state of affairs and schedules the next reasonable thing
-// that needs to be done to move the rezzing process along.
-take_the_next_appropriate_action()
-{
-    // see if the child setup process is still running.
-    if (child_needs_setup || is_recon_pending || (llGetListLength(action_queue) > 0) ) {
-        // we're still waiting on something.  make sure it hasn't timed out.
-        if (!check_for_child_timeout()) return;  // we still have time.
-        // saying this one failed, so we set it such that we are not waiting for kids
-        // or recons or the data cow right now.
-        snooze_counter = 0;
-        if (child_needs_setup) {
-            if (DEBUGGING) log_it("TNAP: child needs setup...");
-            child_needs_setup = FALSE;
-            if (conveyance_mode == ONE_WAY_TRIP) {
-//log_it("TNAP: telling root one way kid is hosed.");
-                // the startup of a child jaunter has failed.  let the root think we're
-                // doing okay so it can get on with its life.
-                llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
-                    REZOLATOR_EVENT_REZZED_CHILD, (string)global_rez_place);
-                return;
-            } else {
-//log_it("TNAP: recon fail for kid needs setup, fall through.");
-            }
-        } else if (is_recon_pending) {
-            // the current reconnaissance drone has crashed apparently.  deal with it.
-            if (DEBUGGING) log_it("TNAP: setting recon pend to false");
-            is_recon_pending = FALSE;
-            return;
-        } else if (llGetListLength(action_queue) > 0) {
-            // action_queue must be non-empty, or we wouldn't be here.
-            list action_rec = pop_action_record();  // what else can we do?
-            if (DEBUGGING) log_it("TNAP: time-out on action: " + (string)action_rec);
-            return;
-        }
-        // proceed to the next steps which are probably remedial.
-    }
-
-    if (DEBUGGING) log_it("TNAP: nothing pending, move things along...");
-
-    // nothing is pending right now.
-    if (conveyance_mode == ONE_WAY_TRIP) {
-        // this means we are done, since the only thing we do is start the kid up.
-        llSetTimerEvent(0.0);
-        return;
-    }
-
-    // if the recon advancement returns true, then we are all set for the next place.
-    if (advance_reconnaissance_position()) return;
-    
-    // if we got to here, then we need to do something about being past end of list...
-
-    if (done_reconnoiter) {
-        // all done with that, so we don't need the timer anymore.
-        llSetTimerEvent(0.0);  // stop coming here.
-        return;  // don't need to do any more.
-    }
-
-    if (trying_hard_cases) {
-        try_the_hard_cases();
-    }
-
-    if (DEBUGGING) log_it("fell completely through TNAP()");
-}
-
-// tries to crack the hard cases using added random jaunt destinations.
-try_the_hard_cases()
-{
-    if (DEBUGGING) log_it("hardcase performing recon re-attempt, name=" + global_destination_name);
-    if (is_prefix(global_destination_name, QUADRANT_TAG_NAME)) {
-//log_it("seeing that " + global_destination_name + " is a generated dest, ignoring.");
-        splice_destination_info(current_recon_index, "#" + (string)current_recon_index,
-            vector_chop(final_destination), VERIFY_UNSAFE_DECIDED);
-        advance_reconnaissance_position();
-        return;
-    }
-    // count that as a failure, since we're not still on our first run through the list.
-    recon_reattempts++;
-    if (recon_reattempts > MAXIMUM_RECON_ATTEMPTS) {
-        // we have totally failed to find a workable pathway.  we'll store the
-        // most simple form of the path back as the one to use.
-        log_it("total failure reaching " + (string)final_destination);
-        splice_destination_info(current_recon_index, "#" + (string)current_recon_index,
-            vector_chop(final_destination), VERIFY_UNSAFE_DECIDED);
-        recon_reattempts = 0;
-        advance_reconnaissance_position();
-        return;
-    }
-    
-    // start the process of finding a good random path.
-    if (!load_random_safe_path()) {
-        // can't get there from anywhere else, so try from here.
-        log_it("could not find a good random path!");
-        scramble_to_find_a_way([]);
-    }
-}
-
-// called to start a jaunter in the appropriate mode.
-rez_requested_child(string object_name, integer conv_mode,
-    integer chat_channel, string destination_name, integer all_dests_count,
-    string target_location)
-{
-    if (DEBUGGING)
-        log_it("rez req: " + object_name + " convey=" + (string)conveyance_mode + " chat=" + (string)chat_channel + " dest=" + destination_name + " fullcount=" + (string)all_dests_count + " targ=" + target_location);
-
-    if (private_id_from_listen) {
-        // toss old listening since we're working on a new deal now.
-        llListenRemove(private_id_from_listen);
-    }
-    // listen to chats on our special channel.
-    private_id_from_listen = llListen(chat_channel, "", NULL_KEY, "");
-    
-    // remember the info so we can tell our new child.
-    conveyance_mode = conv_mode;
-    global_destination_name = destination_name;
-    global_object_name = object_name;  // the object to rez from inventory.
-    private_chat_channel = chat_channel;
-    full_journey = llParseString2List(target_location, [VECTOR_SEPARATOR], []);
-    destinations_total = all_dests_count;
-    global_verifications = [];  // clear any old verifications.
-    integer indy;
-    for (indy = 0; indy < destinations_total; indy++)
-        global_verifications += [ VERIFY_UNTESTED ];
-
-    if (conveyance_mode == RECONNAISSANCE_TRIP) {
-        // we need to start reconnaissance mode.
-        current_recon_index = -1;  // a signal that we haven't started.
-        snooze_counter = 0;
-        is_recon_pending = FALSE;
-        done_reconnoiter = FALSE;
-
-//turned off currently.  doesn't seem to help much.
-if (FALSE) {
-        // experimental: add the quadrants of the sim as destinations.  if some of these
-        // are reachable, then they should help us out.
-        destinations_real = destinations_total;
-        integer x;
-        integer y;
-        for (x = 32; x <= 255; x += 64) {
-            for (y = 32; y <= 255; y += 64) {
-                vector calculated = <x, y, 0.0>;
-                float height = llGround(calculated - llGetPos());
-                calculated.z = height + 64;
-                add_destination(QUADRANT_TAG_NAME + (string)x + "," + (string)y, 
-                    (string)adjust_to_ground(<x, y, 0>, 64), VERIFY_UNTESTED);
-            }
-        }
-}
-
-        take_the_next_appropriate_action();
-    } else {
-        // create the jaunter object for a one way trip.
-        rez_a_jaunter(object_name, ONE_WAY_TRICKY_PARM + chat_channel, conveyance_mode);
-    }
-    llSetTimerEvent(TIMER_PERIOD);
-}
-
-// handles responses about our list coming back from the data cow.
-answer_to_the_cow(string msg, string id, list parms)
-{
-    string tag = llList2String(parms, 0);
-    if (tag != OUR_COW_TAG) return;  // was not for us.
-    parms = llDeleteSubList(parms, 0, 0);  // trim out the tag.
-    list action_record = pop_action_record();
-    integer actyo = extract_action_code(action_record);
-    // get the name out of the set first.
-    list split = llParseString2List(llList2String(parms, 1), [HUFFWARE_ITEM_SEPARATOR], []);
-    
-    if (actyo != AQ_ACQUIRE_BASE_PATH) {
-        // it's very important that when we're acquiring other targets' path components,
-        // we do not mistake that for our own state for the path we're trying to reach.
-        // thus we only record the answer for actions that are about our real target.
-        global_destination_name = llList2String(parms, 0);
-        last_verification = llList2Integer(split, 1);
-        full_journey = prechewed_destinations(llList2String(split, 0));
-        if (DEBUGGING)
-            log_it("just heard verif=" + (string)last_verification + " for " + global_destination_name);
-    }
-
-    if (actyo == AQ_ONEWAY_JAUNTER_VOYAGE) {
-//log_it("one way, saying on chan " + (string)private_chat_channel + " -- " + global_destination_name + " fullj=" + (string)full_journey);
-
-        child_needs_setup = FALSE;  // count off the one we just set up.
-
-        integer indy;  // i told you N times.
-        for (indy = 0; indy < MAX_CHAT_REPEAT; indy++) {
-            llSay(private_chat_channel, CHILD_CHAT_TEXT
-                + global_destination_name
-                + DB_SEPARATOR
-                + llDumpList2String(full_journey, VECTOR_SEPARATOR));
-            // pausing to let our words sink in.
-            llSleep(SLEEPY_TIME);
-        }
-
-        // tell the root jaunter that this kid has been issued.
-        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
-            REZOLATOR_EVENT_REZZED_CHILD, (string)global_rez_place );
-    } else if (actyo == AQ_PREP_RECON_JAUNTER) {
-        // we got info about a place to try.  record the last verif state locally.
-        if (DEBUGGING) log_it("info re destination: verif = " + last_verification);
-        splice_just_verification(current_recon_index, last_verification);
-        if ( (last_verification == VERIFY_UNTESTED)
-                || (trying_hard_cases && (last_verification == VERIFY_UNSAFE_SO_FAR) ) ) {
-            // this one is not tested yet or had problems.  try it now.
-//log_it("testing unchecked locale.");
-            is_recon_pending = TRUE;
-            // if the destination is claiming it's untested, we fix that now untrue statement.
-            if (last_verification == VERIFY_UNTESTED) {
-                splice_destination_info(current_recon_index, "#" + (string)current_recon_index,
-                    llDumpList2String(full_journey, VECTOR_SEPARATOR), VERIFY_UNSAFE_SO_FAR);
-            }
-            if (DEBUGGING)
-                log_it("rezzing jaunter for: name " + global_destination_name + " journ" + (string)full_journey);
-            rez_a_jaunter(global_object_name,
-                RECONNAISSANCE_TRICKY_PARM + private_chat_channel, RECONNAISSANCE_TRIP);
-        } else {
-            // this one doesn't need a recon.
-            is_recon_pending = FALSE;
-//log_it("skipping recon for verif " + (string)last_verification);
-            advance_reconnaissance_position();
-        }
-    } else if (actyo == AQ_CHECK_HARD_CASE) {
-        // we got an answer to our request for a new hard locale to try.
-        // remember the verification state locally.
-        splice_just_verification(current_recon_index, last_verification);
-
-        if ( (last_verification == VERIFY_UNTESTED) || (last_verification == VERIFY_UNSAFE_SO_FAR) ) {
-            // this one is not tested yet or had problems.  try it now.
-            if (DEBUGGING)
-                log_it("testing hard case locale at " + (string)current_recon_index
-                    + " name=" + global_destination_name);
-            final_destination = (vector)llList2String(full_journey, -1);
-            try_the_hard_cases();
-        } else {
-//log_it("check hard case--already safe or decidedly unsafe, skipping.");
-            if (last_verification == VERIFY_SAFE) {
-                good_destinations_counted++;
-                if (!is_prefix(global_destination_name, QUADRANT_TAG_NAME)) {
-                    ungenerated_good_destinations_counted++;
-                }
-            }
-            advance_reconnaissance_position();
-        }
-        take_the_next_appropriate_action();
-    } else if (actyo == AQ_ACQUIRE_BASE_PATH) {
-        // a response with a hopefully good destination arrived; base a path on that.
-        scramble_to_find_a_way(prechewed_destinations(llList2String(split, 0)));
-    }
-}
-
-// looks at the location "look_here" and finds the ground height as the z component
-// of the returned vector (where x and y are copied from "look_here").  if the
-// "height_add_in" is non-zero, it is added to the z component to adjust the ground
-// height by an offset.
-vector adjust_to_ground(vector look_here, float height_add_in)
-{
-    float height = llGround(look_here - llGetPos());
-    look_here.z = height + height_add_in;
-    return look_here;
-}
-
-// tries to come up with a random path that can reach a difficult place.
-scramble_to_find_a_way(list possible_helpful_path)
-{
-    // we were told this was a good pathway, so let's try it.
-    if (randomize_within_range(0.0, 1.0, FALSE) > 0.5) {
-        // if we feel like it, add some huge random vectors in.
-        integer indy;
-        integer how_many = (integer)randomize_within_range(1, 5, FALSE);
-//magic constant above.
-        vector rando = llGetPos();  // start with current place.
-        for (indy = 0; indy < how_many; indy++) {
-            // try to add a random completely other place in the sim.
-            vector other_rando = adjust_to_ground(random_vector(0.0, 256.0, FALSE), 64);
-            rando.z = other_rando.z;
-            // by only changing one axis at a time for x and y, we kind of slide around.
-            // this is considered more beneficial than just jumping randomly.
-            if (randomize_within_range(0.0, 1.0, FALSE) > 0.5) {
-                // this 50% modulates the x.
-                rando.x = other_rando.x;
-            } else {
-                // this other 50% modulates the y.
-                rando.y = other_rando.y;
-            }
-//log_it("scramble: wacky rando: " + vector_chop(rando));
-            possible_helpful_path += [ vector_chop(rando) ];
-        }
-    }
-    if (randomize_within_range(0.0, 1.0, FALSE) > 0.2) {
-        // maybe we also feel like adding a small amount to the final destination,
-        // trying for a hook shot, most of the time.
-//log_it("scramble: addition relative to final destination.");
-        vector rando = adjust_to_ground(final_destination + random_vector(0.0, 8.0, TRUE), 64);
-//magic constant above.
-        possible_helpful_path += [ vector_chop(rando) ];
-    }
-    if ( (final_destination.z < 1000.0) && (randomize_within_range(0.0, 1.0, FALSE) > 0.05) ) {
-//hmmm: is this redundant now?
-        // we very often add a vertical component so as to swoop down on the destination
-        // and hopefully avoid ground fault conditions.
-        possible_helpful_path += [ vector_chop(<final_destination.x, final_destination.y,
-            final_destination.z + 64>) ];
-//magic constant above.
-    }
-    // now finally we add in the real place where we're going.
-    possible_helpful_path += [ vector_chop(final_destination) ];
-    // prepare our state for the new attempt.
-    is_recon_pending = TRUE;
-    snooze_counter = 0;
-    full_journey = possible_helpful_path;
-//log_it("scramble: final guess=" + (string)full_journey);
-    // rez for this nutty test path.
-    rez_a_jaunter(global_object_name,
-        RECONNAISSANCE_TRICKY_PARM + private_chat_channel, RECONNAISSANCE_TRIP);
-}
-
-// this function returns TRUE if we are close enough to the "destination".
-integer close_enough(vector destination)
-{
-    float PROXIMITY_REQUIRED = 0.1;
-        // how close we must be to the target location to call it done.
-        // matches current jaunting library proximity.
-    return (llVecDist(llGetPos(), destination) <= PROXIMITY_REQUIRED);
-}
-
-// records a verification state locally so we can make decisions during testing.
-splice_just_verification(integer index, integer verif_state)
-{
-    if ( (index < 0) || (index >= destinations_total) ) return;  // can't do it.
-    global_verifications = chop_list(global_verifications, 0, index - 1)
-        + [ verif_state ]
-        + chop_list(global_verifications, index + 1, destinations_total - 1);
-}
-
-// replaces an existing entry at the "index" if known (otherwise this should be negative)
-// for the location named "dest_name" if known (otherwise should be a restatement of the
-// numerical index with '#' in front).
-splice_destination_info(integer index, string dest_name, string pathway, integer verif)
-{
-//log_it("splicedest: " + (string)index + " name=" + dest_name + " verif=" + (string)verif + " path=" + pathway);
-    splice_just_verification(index, verif);
-    string new_entry = wrap_item_list([pathway, verif]);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, ADD_ITEM_COMMAND,
-        wrap_parameters([dest_name, new_entry]));
-}
-
-string verification_name(integer enumtype)
-{
-    if (enumtype == VERIFY_SAFE) return "ok";
-    else if (enumtype == VERIFY_UNSAFE_SO_FAR) return "uhh";
-    else if (enumtype == VERIFY_UNSAFE_DECIDED) return "far";
-    // catch-all, including untested.
-    return "?";
-}
-
-// returns true if the slackness counter awaiting things has elapsed.
-integer check_for_child_timeout()
-{
-    if (snooze_counter++ > MAXIMUM_SNOOZES) {
-        // go back to the main state.  we took too long.
-//        log_it("timed out!");
-        llUnSit(llAvatarOnSitTarget());  // don't hang onto the avatar for this error.
-        return TRUE;
-    }
-    return FALSE;
-}
-
-//////////////
-
-// action queue for postponed activities.  the first field held in a list item here
-// is an integer action code.  the format of the remaining parameters is up to the
-// caller, and they can be used as the final parameters for when the queued action
-// gets handled.
-list action_queue;
-
-// looks at the action code at the head of the queue without removing the action.
-integer peek_action_code()
-{
-    list fields = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
-    return extract_action_code(fields);
-}
-
-// extracts the action code from a retrieved list.
-integer extract_action_code(list to_parse) { return llList2Integer(to_parse, 0); }
-
-// removes the current head of the action queue and returns it.
-list pop_action_record()
-{
-    list top_action = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
-    action_queue = llDeleteSubList(action_queue, 0, 0);
-    return top_action;
-}
-
-// adds a new action to the end of the action queue.
-push_action_record(integer action, list added_parms)
-{
-    snooze_counter = 0;  // reset back for new action.
-    action_queue += [ wrap_parameters([action] + added_parms) ];
-}
-
-//////////////
-
-// processes link messages received from support libraries.
-handle_link_message(integer which, integer num, string msg, string id)
-{
-    // maybe it's a piece of data from the data cow.
-    if (num == DATA_COW_HUFFWARE_ID + REPLY_DISTANCE) {
-        // unpack the parameters we were given.
-        list parms_x = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        answer_to_the_cow(msg, id, parms_x);
-        return;
-    }
-    
-    if (num != JAUNT_REZOLATOR_HUFFWARE_ID) return;  // not interesting.
-    if (DEBUGGING) log_it("linkmsg: msg " + msg + " id " + id);
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    if (msg == REZ_CHILD_NOW) {
-        serving_root = TRUE;
-        snooze_counter = 0;  // reset counter.
-        if (llGetListLength(parms) < REZ_KID_FIELDS_NEEDED) {
-//                log_it("insufficient parameters for rezzing child.");
-            return;
-        }
-        rez_requested_child(llList2String(parms, 0), llList2Integer(parms, 1),
-            llList2Integer(parms, 2), llList2String(parms, 3),
-            llList2Integer(parms, 4), llList2String(parms, 5));
-    } else if (msg == REPORT_CHILD_REZZED) {
-        report_to_root();
-    } else if (msg == RESET_REZOLATOR) {
-        llResetScript();
-    } else if (msg == REZOLATOR_CHILD_SUPPORT) {
-        provide_child_support(llList2Integer(parms, 0));
-    } else if (msg == REZOLATOR_CHILD_RETURNED) {
-        if (conveyance_mode == RECONNAISSANCE_TRIP) {
-            // unpack the success value from jaunter's check.
-            integer succeeded_recon = llList2Integer(parms, 0);
-            // report on our success.
-            list report_loc = full_journey;
-            if (!succeeded_recon) {
-                // we did at least get to somewhere, even if not to target.
-                report_loc = llParseString2List(llList2String(parms, 1),
-                    [VECTOR_SEPARATOR], []);
-            }
-            llWhisper(private_chat_channel, CHILD_CHAT_TEXT + RETURN_WORD
-                + (string)succeeded_recon + DB_SEPARATOR
-                + global_destination_name
-                + DB_SEPARATOR
-                + llDumpList2String(report_loc, VECTOR_SEPARATOR));
-//log_it("child reporting success=" + (string)succeeded_recon + " for " + global_destination_name + " via " + llDumpList2String(report_loc, VECTOR_SEPARATOR) );
-            // shuffle off...
-//log_it("now dying at posn " + (string)llGetPos());
-            llDie();  // oh crud, we're toast.
-        } else {
-            // one way trip??
-            if (!succeeded_recon) log_it("too far away; path okay?");
-        }
-    }
-}
-
-// makes our click action change to the type requested, and sends the request
-// out to all our sub-prims also.
-set_click_action(integer action)
-{
-    llSetClickAction(action);
-    // secret message to other prims to change click action.
-    llMessageLinked(LINK_SET, CHANGE_CLICK_ACTION_HUFFWARE_ID, "", (string)action);
-}
-
-// tries to find a known safe locale that's close to the target.  if there are any
-// that are close, then we will not add this location.  otherwise, we do add it,
-// if the list is not already too large.
-add_if_no_close_match(string pathway)
-{
-    // make sure there's enough room to bother checking.
-    if (llGetListLength(safe_locales_seen) >= MAXIMUM_SAFE_LOCATIONS) return;
-    list dests = llParseString2List(pathway, [VECTOR_SEPARATOR], []);
-    vector final_locn = (vector)llList2String(dests, -1);
-    // set the z component to zero for this comparison, which is only about x,y position.
-    // since we then add this trimmed vector, we don't need to worry about the z component
-    // for the items already in the list.
-    final_locn.z = 0;
-    integer i;
-    for (i = 0; i < llGetListLength(safe_locales_seen); i++) {
-        vector curr = (vector)llList2String(safe_locales_seen, i);
-        if (llVecDist(curr, final_locn) < MINIMUM_DISTANCE_FOR_EXTRAS) {
-//log_it("dest too close: dist = " + (string)llVecDist(curr, final_locn));
-            return;
-        }
-    }
-    if (DEBUGGING) log_it("dest far enough to add: " + pathway);
-    // no known locale is close, so we'll add this one.
-    safe_locales_seen += [ final_locn ];
-    good_destinations_counted++;
-    add_destination(QUADRANT_TAG_NAME + "pt#" + (string)(partial_path_count++),
-        pathway, VERIFY_SAFE);
-}
-
-// process what we hear in open chat and on our special channels.
-// this function should always return FALSE unless it's been given enough info
-// to enter a new state, in which case it should return true.
-listen_to_voices(integer channel, string name, key id, string message)
-{
-    // check to see if the text is right.
-    if (DEBUGGING)
-        log_it("heard: " + message + " from " + name);
-    if (!is_prefix(message, CHILD_CHAT_TEXT)) return;  // not right.
-    message = llDeleteSubString(message, 0, llStringLength(CHILD_CHAT_TEXT) - 1);
-    // maybe this is a startup request.
-    if (is_prefix(message, READY_TEXT) && serving_root) {
-        // yes, this is a request for a destination.  we are going to fill the rezzed object
-        // now, so figure out what type of jaunter needs info.  formerly fill_rezzed_object.
-        integer is_recon = (integer)llGetSubString(message, -1, -1);
-        if (done_reconnoiter && is_recon) return;  // we already did all that.
-        if (is_recon) {
-            // a recon jaunter needs its instructions.
-            if (DEBUGGING)
-                log_it("telling recon kid: name " + global_destination_name + " journ=" + (string)full_journey);
-            is_recon_pending = TRUE;
-            integer indy;  // i told you N times.
-            for (indy = 0; indy < MAX_CHAT_REPEAT; indy++) {
-                llSay(private_chat_channel, CHILD_CHAT_TEXT
-                    + global_destination_name
-                    + DB_SEPARATOR
-                    + llDumpList2String(full_journey, VECTOR_SEPARATOR));
-                // snooze to make sure we pause a little between mouthings.
-                llSleep(SLEEPY_TIME);
-            }
-
-            snooze_counter = 0;  // starting over.
-            child_needs_setup = FALSE;  // count off the one we just set up.
-        } else {
-            if (DEBUGGING)
-                log_it("into code for one way jaunter");
-            // simple one way jaunter needs fillin'.
-            list added_parms = [];
-            push_action_record(AQ_ONEWAY_JAUNTER_VOYAGE, added_parms);
-            llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-                wrap_parameters([OUR_COW_TAG, global_destination_name]));
-        }
-        return;
-    }
-
-    if (DEBUGGING) log_it("into kid side of rezolator...");
-
-    if (!serving_root) {
-        if ( (conveyance_mode == RECONNAISSANCE_TRIP) || (conveyance_mode == ONE_WAY_TRIP) ) {
-            if (heard_from_root) return;  // we already did this bit.
-            // this jaunter is destined for short-lived work, but now at least has a goal.
-            // we just pass along the parameters that were told to us from the root jaunter.
-            list parms = llParseString2List(message, [DB_SEPARATOR], []);
-            global_destination_name = llList2String(parms, 0);
-            full_journey = llParseString2List(llList2String(parms, 1), [VECTOR_SEPARATOR], []);
-            final_destination = (vector)llList2String(full_journey, -1);
-            parms += [ conveyance_mode ];
-    
-            if (conveyance_mode == ONE_WAY_TRIP) {
-                // set the click action properly.
-                if (outside_of_sim(final_destination)) set_click_action(CLICK_ACTION_TOUCH);
-                else set_click_action(CLICK_ACTION_SIT);
-            }
-    
-            if (DEBUGGING) log_it("kid heard go to: " + global_destination_name + " via " + (string)full_journey);
-            llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE,
-                REZOLATOR_EVENT_GOT_INSTRUCTIONS, wrap_parameters(parms));
-            // make sure we cancel the listening so we don't hear directions that aren't for us.
-            llListenRemove(private_id_from_listen);
-            heard_from_root = TRUE;
-            return;  // only leave for recon.
-        }
-    } else {
-        // this jaunter's role should be a root jaunter, and we have a reply about a recon mission.
-        is_recon_pending = FALSE;  // we got an acceptable answer.
-        list parms = llParseString2List(llDeleteSubString
-            (message, 0, llStringLength(RETURN_WORD) - 1), [DB_SEPARATOR], []);
-        integer success = llList2Integer(parms, 0);
-        string dest_name = llList2String(parms, 1);
-        string pathway = llList2String(parms, 2);
-//log_it("|||| recon reply: " + dest_name + " good=" + (string)success + " path=" + pathway);
-        if (success) {
-            // record this as a safe pathway.
-            last_verification = VERIFY_SAFE;
-            good_destinations_counted++;
-        } else {
-            // a failure is being reported.  record this as a bad pathway.
-            last_verification = VERIFY_UNSAFE_SO_FAR;
-            // however, the jaunter should have told us where it did get to.  record that whole
-            // thing if it seems like a good distance from our other known good places.
-            if (DEBUGGING) log_it("failed path did get to: " + pathway);
-            add_if_no_close_match(pathway);
-
-        }
-        // only save this info if we're not working on recons.
-        if (!trying_hard_cases || success) {
-            // fix name for tough destination's real one.
-            if (trying_hard_cases) {
-                dest_name = "#" + (string)current_recon_index;
-            }
-            splice_destination_info(current_recon_index, dest_name,
-                llDumpList2String(full_journey,
-                    ///llList2List(full_journey, 1, -1), 
-                VECTOR_SEPARATOR),
-                last_verification);
-        }
-        take_the_next_appropriate_action();
-    }
-}
-
-// processes a destination set to handle special cases, like for offset jaunting.
-list prechewed_destinations(string dests)
-{
-
-//hmmm: document this!  as in, we support the offset format.
-
-    // look for our special start character for offsets.
-    if (is_prefix(dests, "o"))
-        // if this is an offset version, then chop whatever word they used starting with 'o'
-        // and compute the destination based on current position.
-        return [ (vector)llDeleteSubString(dests, 0, find_substring(dests, "<") - 1) + llGetPos() ];
-    else
-        // normal jaunt to absolute coordinates.
-        return llParseString2List(dests, [VECTOR_SEPARATOR], []);
-}
-
-// creates a jaunter object given which inventory item and the startup parm.
-rez_a_jaunter(string object_name, integer rez_parm, integer conveyance_mode)
-{
-    // the minimum and maximum distances for placing the auto-rezzed jaunter object.
-    integer MIN_REZ_DISTANCE = 1;
-    integer MAX_REZ_DISTANCE = 3;
-    vector RECON_ROTATION = <270.0, 0.0, 0.0>;
-        // what angle we use when planting the recon jaunter.
-        // this is tightly coupled to our particular object.
-    vector point_at_jaunter;
-    if (conveyance_mode == RECONNAISSANCE_TRIP) {
-        // we just use our specified rotation.
-        point_at_jaunter = RECON_ROTATION * DEG_TO_RAD;
-        // start at where the jaunter will be when it tries the same path.
-        global_rez_place  = llGetPos();
-    } else {
-        // we randomize the location to avoid people having the objects
-        // in a big pile on top of each other.
-        global_rez_place  = llGetPos()
-            + <randomize_within_range(MIN_REZ_DISTANCE, MAX_REZ_DISTANCE, TRUE),
-                randomize_within_range(MIN_REZ_DISTANCE, MAX_REZ_DISTANCE, TRUE),
-                0.4>;  // pop it up a bit.
-        // aim the temporary ride at the root jaunter.
-        vector aim_back = llGetPos() - global_rez_place;
-        float z_rot = llAtan2(aim_back.y, aim_back.x);
-        // calculate the vector for rotation given the z rotation.
-        point_at_jaunter = <0.0, 0.0, z_rot>;
-    }    
-    llRezObject(object_name, global_rez_place,
-        ZERO_VECTOR, llEuler2Rot(point_at_jaunter), rez_parm);
-    if (conveyance_mode != RECONNAISSANCE_TRIP) {
-        // this model only jaunts to where it gave out the object.  that
-        // should hopefully always work.  but at least if it can't get back,
-        // it's really close by.
-        full_journey = [ vector_chop(llGetPos()), vector_chop(global_rez_place) ];
-    }
-    child_needs_setup = TRUE;  // we aren't ready to go even if jaunt is done.
-    snooze_counter = 0;  // amnesty on the timer.
-}
-
-// finds a pathway that's already in our list and that we think is safe.
-integer load_random_safe_path()
-{
-    integer indy;
-    integer goodunz = good_destinations_counted;
-
-    // now that we know how many are safe, we can pick a good destination.
-    integer randola = llRound(randomize_within_range(0, goodunz - 1, FALSE));
-    integer safe_indy = -1;  // tracks which safe item we're at.
-    for (indy = 0; indy < llGetListLength(global_verifications); indy++) {
-        // scoot across the list to find the Nth safe one.
-        if (llList2Integer(global_verifications, indy) == VERIFY_SAFE) {
-            if (safe_indy == randola) {
-//log_it("like path at " + (string)safe_indy);
-                // we're at the Nth safe item, so this is our random choice.
-                list added_parms = [];
-                push_action_record(AQ_ACQUIRE_BASE_PATH, added_parms);
-                llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-                    wrap_parameters([OUR_COW_TAG, "#" + (string)safe_indy]));
-                return TRUE;
-            }
-            // increment to the next position, since we've seen this one.
-            safe_indy++;
-        }
-    }
-//log_it("found no good path to use");
-    return FALSE;
-}
-
-// processes the timer events during an ongoing rezzing process.
-handle_timer()
-{
-    // this is the root's timer process, which is implemented in great detail
-    // in the function below.
-    if (serving_root) take_the_next_appropriate_action();
-}
-
-// file a report with the root jaunter that the child has been created and is
-// ready for service.
-report_to_root()
-{
-    // tell the root jaunter know that we're ready to be packed for our trip.
-    llSay(private_chat_channel, CHILD_CHAT_TEXT + READY_TEXT
-        + (string)(conveyance_mode == RECONNAISSANCE_TRIP));
-}
-
-// plops a new destination on the end of the lists.
-add_destination(string name, string path, integer verif)
-{
-//log_it("adding " + name + " with path " + path + " and verif=" + (string)verif);
-    global_verifications += [ verif ];
-    // send our new information to the data cow.  we store the information encoded as
-    // two separated items, where the first element is the destination and the second
-    // is the verification state.
-    string new_entry = wrap_item_list([path, verif]);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, ADD_ITEM_COMMAND,
-        wrap_parameters([name, new_entry]));
-    destinations_total++;  // we just added another destination.
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-// returns TRUE if the "to_check" vector is a location outside of the current sim.
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-// returns text for a floating point number, but includes only
-// two digits after the decimal point.
-string float_chop(float to_show)
-{
-    integer mant = llAbs(llRound(to_show * 100.0) / 100);
-    string neg_sign;
-    if (to_show < 0.0) neg_sign = "-";
-    string dec_s = (string)((llRound(to_show * 100.0) - mant * 100) / 100.0);
-    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
-    // strip off all trailing zeros.
-    while (llGetSubString(dec_s, -1, -1) == "0")
-        dec_s = llDeleteSubString(dec_s, -1, -1);
-    string to_return = neg_sign + (string)mant;
-    if (llStringLength(dec_s)) to_return += "." + dec_s;
-    return to_return;
-}
-
-// returns a prettier form for vector text, with chopped floats.
-string vector_chop(vector to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ">";
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{
-    string full_lower = llToLower(full_string);
-    return llSubStringIndex(full_lower, pattern);
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); initialize_rezolator(); }
-
-    on_rez(integer startup) { llResetScript(); }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-
-    listen(integer channel, string name, key id, string message)
-    { listen_to_voices(channel, name, id, message); }
-
-    timer() { handle_timer(); }
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunt_wik_rez_v86.3.lsl b/huffware/huffotronic_jaunter_updater_v5.1/jaunt_wik_rez_v86.3.lsl
new file mode 100755 (executable)
index 0000000..f8273c1
--- /dev/null
@@ -0,0 +1,1205 @@
+
+// huffware script: jaunt wik rez, by fred huffhines,  released under GPL license.
+//
+// this is a jaunter (teleporter) script with some useful and uncommon features.
+// it can work around certain types of complicated land permissions on neighboring land
+// that might otherwise lead to blocked jaunts.
+// the usage of "jaunt" for teleportation is inspired by the alfred bester novel, "the stars
+// my destination".  if you like science fiction and have not read this book, it is highly
+// recommended.
+// parts of this script are based on "Teleporter Script v 3.0 by Asira Sakai", from
+// the LSL wiki.
+//
+// use jaunt wik rez by placing a notecard in the inventory of your jaunter object.  the notecard
+// should start with "#jaunt" on the first line and then should have alternating lines of
+// (1) jaunt target (as a vector) and (2) readable target name, for example:
+//      #jaunt
+//      <23, 18, 92>
+//      gracy square
+//      <182, 32, 56>
+//      tourmaline palace
+//      <23, 18, 92>|<118, 19, 108>|<120, 33, 57>
+//      unblocked pathway, hurrah
+// note the last destination; the script also supports a list of intermediate destinations.
+// this feature can enable one to route a teleport around blocked lands by using waypoints
+// that are still accessible.  but since the current version of the script automatically
+// finds routes for most destinations, this is not needed very frequently.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+
+integer DEBUGGING = FALSE;
+    // make true to print diagnostic logging.
+
+// configurable options (set in notecard):
+
+integer SHOW_TEXT = TRUE;
+    // if true, then the jaunter will show a text label for the destination.
+    // this can be configured from the notecard with ":show_text=0" to turn off,
+    // or 1 to turn on.
+integer ADD_NAME = FALSE;
+    // if this is true, then the text shown will include the object's name.
+
+string TEXT_COLOR = "<0.3, 0.9, 0.7>";
+    // set float text color to a nice color.
+///hmmm: doesn't seem to be in the notecard yet!
+
+//////////////
+
+// the jaunter button pushing API.
+//////////////
+integer BUTTON_PUSHER_HUFFWARE_ID = 10029;
+    // a unique ID within the huffware system for this script.
+//////////////
+string BUTTON_PUSHED_ALERT = "#btnp";
+    // this event is generated when the button is pushed.  the number parameter will be
+    // the huffware id plus the reply distance.  the id parameter in the link message will
+    // contain the name of the button that was 
+string JAUNT_NEXT_BUTTON_NAME = "next";
+string JAUNT_MENU_BUTTON_NAME = "menu";
+
+//////////////
+    
+// requires the jaunt config API.
+//////////////
+// do not redefine these constants.
+integer JAUNT_CONFIGURATION_HUFFWARE_ID = 10022;
+    // the unique id within the huffware system for this script's commands.
+    // it's used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+// commands available from the jaunt config library:
+string LOAD_ALL_CONFIGURATIONS = "#rdcfg#";
+    // this starts the process of loading jaunt destinations from the notecards and
+    // landmarks that we find in the object.  the parms are: private channel
+    // and conveyance mode.
+string JAUNT_CFG_DATA_EVENT = "#yodata#";
+    // this event is generated from this script back to the caller.  when we have some
+    // landmark data or configuration information, it's passed back in chunks.  the
+    // deluge of pieces will continue until the JAUNT_CFG_EOF event is passed.  the
+    // parameters include packed destination name and vector pairs (which form 2 elements
+    // in the list) and packed config variable definitions (where config items start
+    // with a colon, and the definition is only one element in the list).
+string JAUNT_CFG_EOF = "#done#";
+    // sent after all valid configuration items that we could find were processed.
+//
+//////////////
+
+// requires jaunting library API.
+//////////////
+// do not redefine these constants.
+integer JAUNT_HUFFWARE_ID = 10008;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+//////////////
+// commands available via the jaunting library:
+string FULL_STOP_COMMAND = "#fullstop#";
+    // command used to bring object to a halt.
+string JAUNT_LIST_COMMAND = "#jauntlist#";
+    // like regular jaunt, but expects a string in jaunt notecard format with vectors.
+    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
+//
+//////////////
+
+// requires menutini API.
+//////////////
+// do not redefine these constants.
+integer MENUTINI_HUFFWARE_ID = 10009;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string SHOW_MENU_COMMAND = "#menu#";
+    // the command that tells menutini to show a menu defined by parameters
+    // that are passed along.  these must be: the menu name, the menu's title
+    // (which is really the info to show as content in the main box of the menu),
+    // the wrapped list of commands to show as menu buttons, the menu system
+    // channel's for listening, and the key to listen to.
+
+// requires data cow library API.
+//////////////
+// do not redefine these constants.
+integer DATA_COW_HUFFWARE_ID = 10017;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+//////////////
+string RESET_LIST_COMMAND = "reset_L";
+    // flushes out the currently held list.  does not send a reply.
+string ADD_ITEM_COMMAND = "add_I";
+    // adds items to the list.  this is a list of pairs of name/value, where the name is
+    // how the item will be looked up from the list, and the value is the contents to be stored.
+    // this command has no reply.
+string GET_COW_LENGTH = "get_Lc";
+    // returns a single integer which is the length of the cow's list currently.
+//string REMOVE_ITEM_COMMAND = "rm_I";
+    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
+    // this command also has no reply.
+//string GET_ITEM_COMMAND = "get_I";
+    // retrieves the item's contents for a given name.  first parm is the name.  if there
+    // are other parameters, then they are taken as other items to return also.
+    // the return data will be pairs of <name, entry> for each of the names in the request.
+    // if the data was not located, then the entry will be empty.
+string TAGGED_GET_ITEM_COMMAND = "get_T";
+    // like get item, except the first parameter is an identifier that the caller wants to
+    // use to tag this request.  the other parameters are still taken as names.  the response
+    // will contain the tag as the first item, then the <name, entry> pairs that were found.
+
+//////////////
+
+// requires click action API...
+//////////////
+integer CHANGE_CLICK_ACTION_HUFFWARE_ID = 10024;
+    // a unique ID within the huffware system for this script.
+// the API only supports the service number; there are no commands to pass in the "msg"
+// parameter.  the id does accept a parameter, which is the type of click action to begin
+// using for this prim.
+//////////////
+
+// the API for this library script to be used in other scripts.
+//////////////
+// do not redefine these constants.
+integer JAUNT_REZOLATOR_HUFFWARE_ID = 10025;
+    // the unique id within the huffware system for this script's commands.
+    // it's used in llMessageLinked as the num parameter.
+//////////////
+// commands available from the library:
+string RESET_REZOLATOR = "#reset";
+    // tells the script to stop any previous efforts to rez children.
+string REZ_CHILD_NOW = "#rezkd#";
+    // requests this script to create a new child object.  this requires several
+    // parameters to succeed: 1) object to rez, 2) conveyance mode for the rezzed object
+    // to implement, 3) the chat channel to listen for and speak to new child on,
+    // 4) the destination name for where the child should go, 5) a count of the full
+    // set of known destinations, 6) the target where the jaunt should arrive at.
+//////////////
+// events generated by the library:
+string REZOLATOR_EVENT_REZZED_CHILD = "#donekd";
+    // an event generated for a previous rez child request.  this lets the caller know that
+    // the child has been created and told what to do.  the single parameter is where the
+    // jaunter has been rezzed.
+string REZOLATOR_EVENT_RECON_FINISHED = "#rzcnfn";
+    // an event generated when the recon process has concluded.  this includes parms:
+    // number of good destinations.
+//
+//////////////
+
+// important constants used internally...  these should not be changed willy nilly.
+
+////////////// jaunt base API
+
+// the following constants define how the script should behave (i.e., its conveyance mode).
+// TWO_WAY_TRIP: the script jaunts using the current target vectors to get somewhere
+//   and then takes the same pathway back, but in reverse order.
+// AUTOREZ_JAUNTER: the script rezzes the first regular object in its inventory next to
+//   the root telehub.  that object is loaded with the destination notecard and this script.
+//   the rezzed object can then be used for the next few minutes to jaunt to the selected
+//   destination.  the temporary object will use the ONE_WAY_TRIP mode.
+// ONE_WAY_TRIP: the object containing this script will take the user to a particular
+//   destination, but the object does not survive the trip.  it self-destructs after
+//   reaching the destination.  this mode is used in conjunction with the AUTOREZ_JAUNTER
+//   mode and should generally never be used on its own.
+// RECONNAISSANCE_TRIP: a survey run to test out a particular path to get to a
+//   destination.
+integer TWO_WAY_TRIP = 1;
+integer AUTOREZ_JAUNTER = 2;
+integer ONE_WAY_TRIP = 3;
+integer RECONNAISSANCE_TRIP = 4;
+
+// values used to represent different stages of verification.
+integer VERIFY_UNTESTED = -3;  // don't know destinations state yet.
+integer VERIFY_SAFE = -4;  // the destination last tested safe.
+integer VERIFY_UNSAFE_SO_FAR = -5;  // this cannot be done with simple jaunt.
+integer VERIFY_UNSAFE_DECIDED = -6;  // this means the destination seems intractable.
+
+integer MAXIMUM_PRIV_CHAN = 90000;
+    // the largest amount we will ever subtract from the tricky parms in order to
+    // tell the sub-jaunter which channel to listen on.
+
+string VECTOR_SEPARATOR = "|";
+    // how we separate components of vectors from each other.
+string DB_SEPARATOR = "``";  // separating items in lists.
+
+////////////// end jaunt base API
+
+integer MAX_DEST_NAME = 24;  // the longest name that we store.
+
+float NORMAL_TIMER_PERIOD = 1.0;  // our normal timer rate.
+
+string RESET_COMMAND = "jreset";  // forget everything and start over.
+string SHOW_COMMAND = "show";  // describe the known destinations.
+string RECON_COMMAND = "recon";  // tells the jaunter to run reconnaissance on destinations.
+
+float POSITION_CHECKING_INTERVAL = 0.11;
+    // how frequently the waiting for arrival state will check where we are.
+
+integer MAXIMUM_SLACKNESS = 108;
+    // how many timer hits we'll allow before reverting to the default state.
+
+integer FREE_MEM_REQUIRED = 1600;
+    // we need at least this much memory before adding new targets.
+
+// somewhere between two and 10 minutes (default) will elapse before first recon testing.
+float MIN_RECON_SNOOZE = 120;
+float MAX_RECON_SNOOZE = 1200;
+
+// the actions that can be held in the action queue.
+integer AQ_SHOW_DEST_RECORD = 23;  // a record to be shown to the user.
+integer AQ_FINISH_SHOW_DESTS = 24;  // last record in a jaunt destinations list.
+integer AQ_CLICK_ACTION_REQUEST = 25;  // the response should set our click action.
+integer AQ_SELECT_DESTINATION = 27;  // the user has chosen a different destination.
+integer AQ_DONE_CONFIGURING = 28;  // the last step of the configuration process has finished.
+
+string OUR_COW_TAG = "jwkrz_dc";  // unique id for this script to talk to the data cow with.
+
+//////////////
+
+// global variables.
+
+integer private_chat_channel;  // where sub-jaunters communicate with root.
+integer conveyance_mode;  /// = TWO_WAY_TRIP;
+    // default is a standard two way trip, there and back again.  note that the object
+    // will fail to return if any lands in between are blocking object entry.  those
+    // situations should use an auto-rez jaunter, which is specified by prefixing the
+    // target vectors with AR.
+integer last_verification_state;  // the verification state of the last destination we asked for.
+string last_pathway;  // similar, but the last pathway we heard.
+integer current_target_index;  // the location in the list that we would currently jaunt to.
+
+integer good_destinations;  // computed during the recon process.
+
+// jaunter target configuration...
+list global_names;  // the names for each destination.
+
+// jaunt trip variables...
+vector eventual_destination;  // where we're headed, if we're headed anywhere.
+integer slackness_counter;  // snoozes had while waiting for destination.
+list full_journey;  // the full pathway we expect to jaunt on.
+integer jaunt_responses_awaited;  // number of pending jumps in progress.
+
+// root jaunter variables...
+integer child_needs_setup;
+    // true when a child has been rezzed and still needs to be filled with the script.
+
+integer recon_started_yet = FALSE;
+    // true if we've finished running through the reconnaissance process yet.
+
+//////////////
+
+// makes our click action change to the type requested, and sends the request
+// out to all our sub-prims also.
+set_click_action(integer action)
+{
+    llSetClickAction(action);
+    // secret message to other prims to change click action.
+    llMessageLinked(LINK_SET, CHANGE_CLICK_ACTION_HUFFWARE_ID, "", (string)action);
+}
+
+integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
+
+// show the list of options for someone who used the click-hold feature.
+show_jaunt_menu(key last_toucher)
+{
+    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
+        "jm" + HUFFWARE_PARM_SEPARATOR
+        + "Jaunt to..." + HUFFWARE_PARM_SEPARATOR
+        + wrap_item_list(global_names)
+        + HUFFWARE_PARM_SEPARATOR
+        + (string)random_channel() + HUFFWARE_PARM_SEPARATOR
+        + (string)last_toucher);
+}
+
+// respond to the user's choice.
+react_to_menu(string which_choice)
+{
+    integer indy;
+    // find the specified destination and select it.
+    indy = llListFindList(global_names, [which_choice]);
+    if (indy >= 0) {
+        current_target_index = indy;
+        select_destination(current_target_index);
+    }
+}
+
+// asks the jaunting library to take us to the target using a list of waypoints.
+request_jaunt(list journey, integer forwards)
+{
+    // ask for a jump.
+    jaunt_responses_awaited++;
+    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_LIST_COMMAND,
+        wrap_item_list(journey) + HUFFWARE_PARM_SEPARATOR + (string)forwards);
+    // stops the jaunter in its tracks.
+    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, FULL_STOP_COMMAND, ""); 
+}
+
+// this function returns TRUE if we are close enough to the "destination".
+integer close_enough(vector destination)
+{
+    float PROXIMITY_REQUIRED = 0.1;
+        // how close we must be to the target location to call it done.
+        // matches current jaunting library proximity.
+    return (llVecDist(llGetPos(), destination) <= PROXIMITY_REQUIRED);
+}
+
+// returns appropriate sit text for our current jaunt mode.
+string sit_text()
+{
+    if (conveyance_mode == AUTOREZ_JAUNTER) return "Rez Ride";
+    return "Jaunt";
+}
+
+// plops a new destination on the end of the lists.
+add_destination(string name, string path, integer verif)
+{
+//    if (DEBUGGING) log_it("adding " + name + " with path " + path);
+    global_names += [ name ];
+    // send our new information to the data cow.  we store the information encoded as
+    // two separated items, where the first element is the destination and the second
+    // is the verification state.
+    string new_entry = wrap_item_list([path, verif]);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, ADD_ITEM_COMMAND,
+        wrap_parameters([name, new_entry]));
+}
+
+// sets up the initial state, if this script has just started, or it
+// cleans up the state, if the script was already running.
+initialize_jaunter()
+{
+    llSetTimerEvent(0.0);  // cancel any existing timers.
+
+    // reset all the important variables.
+    global_names = [];
+    current_target_index = 0;
+    good_destinations = 0;
+
+    llSitTarget(<0, 0, 0.1>, ZERO_ROTATION);
+        // set a rudimentary sit target or opensim won't give us our changed events.
+    // load up an arrival sound if any exist.
+    if (llGetInventoryNumber(INVENTORY_SOUND))
+        llPreloadSound(llGetInventoryName(INVENTORY_SOUND, 0));
+    // reset the parallel processing scripts since we've restarted.
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, RESET_LIST_COMMAND, "");
+    llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, RESET_REZOLATOR, "");
+    
+    // see if we can load our configuration from notecards and landmarks.
+    // we pick a private channel that fits in between our rez parm ranges.
+    private_chat_channel = (integer)randomize_within_range(-MAXIMUM_PRIV_CHAN, -1, FALSE);
+    // request that all the config get loaded up.
+    llMessageLinked(LINK_THIS, JAUNT_CONFIGURATION_HUFFWARE_ID, LOAD_ALL_CONFIGURATIONS,
+         wrap_parameters([private_chat_channel, conveyance_mode]));
+    // during a normal trip, we will make sure the notecard reading doesn't stall.
+    // the recon and one way jaunters don't need this; they're temporary.
+    // we allow this number of seconds before notecard reader is awol.
+    llSetTimerEvent(94);
+
+    conveyance_mode = TWO_WAY_TRIP;  // default init in opensim friendly way.
+
+    // set up some of the object properties...
+    string msg;
+    if (SHOW_TEXT) msg = "?...";
+    llSetText(msg, (vector)TEXT_COLOR, 1.0);  // initial floating text for jaunter.
+    llSetSitText(sit_text());  // change to the proper text for our mode.
+}
+
+init_normal_runtime()
+{
+    child_needs_setup = FALSE;
+    // listen to the general public for commands.
+    llListen(0, "", NULL_KEY, "");
+    // set up a root jaunter.
+    recon_started_yet = FALSE;        
+    llSetTimerEvent(randomize_within_range(MIN_RECON_SNOOZE, MAX_RECON_SNOOZE, FALSE));
+}
+
+// signal that we are where we were going.
+proclaim_arrival()
+{
+    if (conveyance_mode == TWO_WAY_TRIP) {
+        // sing a little song, if there's a sound to use.
+        if (llGetInventoryNumber(INVENTORY_SOUND))
+            llTriggerSound(llGetInventoryName(INVENTORY_SOUND, 0), 1.0);
+    }
+}
+
+string verification_name(integer enumtype)
+{
+    if (enumtype == VERIFY_SAFE) return "ok";
+    else if (enumtype == VERIFY_UNSAFE_SO_FAR) return "uhh";
+    else if (enumtype == VERIFY_UNSAFE_DECIDED) return "far";
+    // catch-all, including untested.
+    return "?";
+}
+
+// returns true if the slackness counter awaiting things has elapsed.
+integer check_for_timeout()
+{
+    if (slackness_counter++ > MAXIMUM_SLACKNESS) {
+        // go back to the main state.  we took too long.
+        log_it("timed out!");
+        llUnSit(llAvatarOnSitTarget());  // don't hang onto the avatar for this error.
+        llSetTimerEvent(0.0);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+//////////////
+
+// action queue for postponed activities.  the first field held in a list item here
+// is an integer action code.  the format of the remaining parameters is up to the
+// caller, and they can be used as the final parameters for when the queued action
+// gets handled.
+list action_queue;
+
+// looks at the action code at the head of the queue without removing the action.
+integer peek_action_code()
+{
+    list fields = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
+    return extract_action_code(fields);
+}
+
+// extracts the action code from a retrieved list.
+integer extract_action_code(list to_parse) { return llList2Integer(to_parse, 0); }
+
+// removes the current head of the action queue and returns it.
+list pop_action_record()
+{
+    if (llGetListLength(action_queue) == 0) {
+//        if (DEBUGGING) log_it("failure in action q: no entries.");
+        return [];
+    }
+    list top_action = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
+    action_queue = llDeleteSubList(action_queue, 0, 0);
+    jaunt_responses_awaited--;  // one less thing to wait for.
+    return top_action;
+}
+
+// adds a new action to the end of the action queue.
+push_action_record(integer action, list added_parms)
+{
+    action_queue += [ wrap_parameters([action] + added_parms) ];
+    jaunt_responses_awaited++;  // add one counter to our pending responses.
+}
+
+//////////////
+
+string show_buffer;  // used by the destination list showing code below.
+
+// requests a dump of all the jaunt destinations so we can show them to the user.
+get_destination_records()
+{
+    show_buffer = "[mem " + (string)llGetFreeMemory() + "]";  // set the first line in the output.
+    
+    integer indy;
+    for (indy = 0; indy < llGetListLength(global_names); indy++) {
+        string curr = llList2String(global_names, indy);
+        // ask for this destination record.
+        llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+            wrap_parameters([OUR_COW_TAG, curr]));
+        integer action = AQ_SHOW_DEST_RECORD;
+        if (indy == llGetListLength(global_names) - 1) {
+            // if it's the last item, make sure we signal that.
+            action = AQ_FINISH_SHOW_DESTS;
+        }
+        push_action_record(action, []);
+    }
+}
+
+// displays the list of destinations in normal chat that the data cow is handing us.
+show_destination_record(string loc_name, string pathway, integer verif, integer action)
+{
+    integer MAX_CHAT = 512;  // the largest we let the buffer get before saying it.
+    show_buffer += "   " + loc_name + " ("
+        + verification_name(verif) + ") â†£ " + pathway;
+    // if we're done, add a note about quality of targets.
+    if (action == AQ_FINISH_SHOW_DESTS) {
+        show_buffer += "\n  (" + (string)good_destinations + " safe & "
+            + (string)(llGetListLength(global_names) - good_destinations)
+            + " tough ones)";
+    }
+        
+    // if we're done or if the string gets too big, print and reset it.
+    if ( (action == AQ_FINISH_SHOW_DESTS) || (llStringLength(show_buffer) >= MAX_CHAT) ) {
+        llWhisper(0, show_buffer);
+        show_buffer = "";
+    }
+}
+
+// returns the value of a boolean variable definition.
+integer parse_bool_def(string def)
+{ return !(llGetSubString(def, find_substring(def, "=") + 1, -1) == "0"); }
+
+// processes a configuration option from the notecard.
+handle_config_item(string item)
+{
+    item = llGetSubString(item, 1, -1);  // chop the command signifier character.
+    if (is_prefix(item, "show_text")) {
+        // they are controlling whether to show the text label or not.
+        SHOW_TEXT = parse_bool_def(item);
+    } else if (is_prefix(item, "add_name")) {
+        ADD_NAME = parse_bool_def(item);
+    }
+}
+
+// processes items coming from the configuration library.
+consume_configuration_items(string msg, string id)
+{
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    integer mem_okay = llGetFreeMemory() >= FREE_MEM_REQUIRED;  // false if we're low on memory.
+    if (!mem_okay) return;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(parms); indy += 2) {
+        string name = llList2String(parms, indy);
+        if (is_prefix(name, ":")) {
+            handle_config_item(name);
+            indy--;  // skip back so we continue looking for destinations.
+        } else {
+            // this should be a normal pair of destination vector and name.
+            integer verif_state = VERIFY_UNTESTED;
+            // check if it's a wacky location.
+            string map_coord = llList2String(parms, indy + 1);
+            list chewed = chewed_destination(map_coord);
+            if (outside_of_sim((vector)llList2String(chewed, 0))) {
+                if (DEBUGGING) log_it("ruled map_coor " + (string)map_coord + " out of sim.");
+                // make sure we consider the tp location "unsafe", since we can't run in-sim
+                // reconnaissance against it.  also, we must postpone marking it until
+                // the destination is listed, given current implementation.
+                verif_state = VERIFY_UNSAFE_DECIDED;
+            }
+            add_destination(name, llList2String(parms, indy + 1), verif_state);
+        }
+    }
+}
+
+// handles responses about our list coming back from the data cow.
+integer answer_to_the_cow(string msg, string id, list parms)
+{
+    string tag = llList2String(parms, 0);
+    if (tag != OUR_COW_TAG) return FALSE;  // was not for us.
+    parms = llDeleteSubList(parms, 0, 0);  // trim out the tag.
+    list action_record = pop_action_record();
+    integer actyo = extract_action_code(action_record);
+    list split = llParseString2List(llList2String(parms, 1), [HUFFWARE_ITEM_SEPARATOR], []);
+    if ( (actyo == AQ_SHOW_DEST_RECORD) || (actyo == AQ_FINISH_SHOW_DESTS) ) {
+        show_destination_record(llList2String(parms, 0), llList2String(split, 0),
+            llList2Integer(split, 1), actyo);
+    } else if (actyo == AQ_CLICK_ACTION_REQUEST) {
+        // make sure we're in the right mode for clicking based on how
+        // many destinations we have.  if there's only one, we might as
+        // well make this jaunter just go there.
+        // note: just discovered that we cannot set the click action if the jaunter
+        // is multiple prims.  that's totally fubar.  it means we cannot correctly
+        // set the jaunter main body to show 'sit' as the option, even when jaunting
+        // directly to the destination is possible.  freaking lindens.  maybe osgrid
+        // will fix this someday.
+        if (llGetListLength(global_names) == 1) {
+            if (llList2Integer(split, 1) != VERIFY_UNSAFE_DECIDED)
+                set_click_action(CLICK_ACTION_SIT);
+            else
+                // we have a non-local jaunter, so set up for map clicking.
+                set_click_action(CLICK_ACTION_TOUCH);
+        } else set_click_action(CLICK_ACTION_TOUCH);
+    } else if (actyo == AQ_SELECT_DESTINATION) {
+        integer verif = llList2Integer(split, 1);
+        // we only switch conveyance mode if we have not been told to
+        // do the one-way trip or recon.
+        if (verif == VERIFY_SAFE) conveyance_mode = TWO_WAY_TRIP;
+        else conveyance_mode = AUTOREZ_JAUNTER;
+        llSetSitText(sit_text());  // change to the proper text for our mode.
+        full_journey = [ vector_chop(llGetPos()) ] + chewed_destination(llList2String(split, 0));
+        integer last_selecting_index = llList2Integer(action_record, 1);
+        string destname = llList2String(global_names, last_selecting_index);
+        llWhisper(0, "Next stop: " + destname);
+        text_label_for_destination(destname);
+        last_verification_state = verif;
+        last_pathway = llList2String(split, 0);
+    } else if (actyo == AQ_DONE_CONFIGURING) {
+        // done with notecard reading, but we still need reconnaissance.
+        // we'll do that in the normal runtime state.
+        return TRUE;        
+    }
+    return FALSE;  // unknown request or a fall-through.
+}
+
+// asks the data cow for our current set of configured destinations and their
+// requisite click actions.
+request_destinations()
+{
+    push_action_record(AQ_CLICK_ACTION_REQUEST, []);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+        wrap_parameters([OUR_COW_TAG, llList2String(global_names, 0)]));
+}
+
+// processes link messages received from support libraries.
+integer handle_link_message(integer which, integer num, string msg, string id)
+{
+    // is it an answer about our configuration?
+    if (num == JAUNT_CONFIGURATION_HUFFWARE_ID + REPLY_DISTANCE) {
+        if (msg == JAUNT_CFG_DATA_EVENT) {
+            // eat these configuration items we were given.
+            consume_configuration_items(msg, id);
+        } else if (msg == JAUNT_CFG_EOF) {
+            // we have finished up on the configuration.
+            completed_configuration();
+        }
+        return FALSE;
+    }
+    
+    // is it a jaunting library response?
+    if (num == JAUNT_HUFFWARE_ID + REPLY_DISTANCE) {
+        jaunt_responses_awaited--;  // one less response being awaited.
+        if (jaunt_responses_awaited < 0) {
+            if (DEBUGGING) log_it("error: j-rsp-awtd<0");
+            jaunt_responses_awaited = 0;
+        }
+        return FALSE;
+    }
+    
+    // is it an event from the rezolator script?
+    if (num == JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        if (msg == REZOLATOR_EVENT_REZZED_CHILD) {
+            // we know the child is ready for us now.
+            child_needs_setup = FALSE;
+//            if (DEBUGGING) log_it("setting journey to rez place " + vector_chop(llGetPos()));
+            full_journey = [ vector_chop(llGetPos()), llList2String(parms, 0) ];
+            if (DEBUGGING) log_it("heard kid is ready, helping.");
+            request_jaunt(full_journey, TRUE);
+            eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
+            llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+        } else if (msg == REZOLATOR_EVENT_RECON_FINISHED) {
+            good_destinations = llList2Integer(parms, 0);
+            if (DEBUGGING) log_it("recon finished, total=" + llGetListLength(global_names) + " good=" + good_destinations);
+            request_destinations();
+            select_destination(current_target_index);
+        }
+        return FALSE;
+    }
+
+    // is this a menu response from the user?
+    if (num == MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) {
+        // all we care about in our parms is the choice made.
+        react_to_menu(llList2String(llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []), 1));
+        return FALSE;
+    }
+    // or maybe it's a piece of data from the data cow.
+    if (num == DATA_COW_HUFFWARE_ID + REPLY_DISTANCE) {
+        return answer_to_the_cow(msg, id, llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []));
+    }
+    // perhaps it's a click on a button.
+    if (num == BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE) {
+        if (msg == BUTTON_PUSHED_ALERT) {
+            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+            if (llList2String(parms, 0) == JAUNT_NEXT_BUTTON_NAME) {
+                select_next_destination();
+            } else if (llList2String(parms, 0) == JAUNT_MENU_BUTTON_NAME) {
+                show_jaunt_menu(llList2String(parms, 1));
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+// make some noise about getting configured right.
+completed_configuration()
+{
+    current_target_index = 0;  // set proper index.    
+    get_destination_records();
+
+    // set up the first destination.
+    select_destination(current_target_index);
+
+    // schedule the request asking how many destinations there are.
+    request_destinations();
+/*    push_action_record(AQ_CLICK_ACTION_REQUEST, []);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+        wrap_parameters([OUR_COW_TAG, llList2String(global_names, 0)]));*/
+
+    // add an item in the queue to actually begin jaunt services.
+    push_action_record(AQ_DONE_CONFIGURING, []);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+            wrap_parameters([OUR_COW_TAG, llList2String(global_names, 0)]));
+}
+
+// process what we hear in open chat and on our special channels.
+// this function should always return FALSE unless it's been given enough info
+// to enter a new state, in which case it should return true.
+integer listen_to_voices(integer channel, string name, key id, string message)
+{
+    if (channel == 0) {
+        // provide common command handling.
+        if (message == SHOW_COMMAND) {
+            // anyone can use this command.
+            get_destination_records();
+            return FALSE;
+        }
+        // the rest of the commands only listen to the owner.
+        if (id != llGetOwner()) return FALSE;
+        if (message == RESET_COMMAND) llResetScript();
+        else if (message == RECON_COMMAND) {
+            // if they want a recon, we'll do it right away.
+            recon_started_yet = FALSE;
+            // we want to reset the rezolator's state, in case it had done this before.
+            llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, RESET_REZOLATOR, "");
+            llSetTimerEvent(0.4);
+        }
+        return FALSE;
+    }
+
+    return FALSE;  // we do not want to go to next state; stay in current one.
+}
+
+// shows our next target for jaunting above the object.
+text_label_for_destination(string target)
+{
+    string msg;
+    if (SHOW_TEXT) {
+        if (ADD_NAME) msg += llGetObjectName() + ":\n";
+        msg += "↣ " + target;
+    }
+    llSetText(msg, (vector)TEXT_COLOR, 1.0);
+}
+
+select_next_destination()
+{
+    // picks the next place in the list for the destination, or wraps around.
+    current_target_index++;
+    if (current_target_index >= llGetListLength(global_names))
+        current_target_index = 0;
+    select_destination(current_target_index);
+}
+        
+touchy_feely()
+{
+    // check the safety of the target and show the map if the conditions are right.
+    vector check_posn = (vector)llList2String(chewed_destination(last_pathway), 0);
+///    if (outside_of_sim(check_posn)) {
+    /////old && (llGetListLength(global_names) == 1) ) {
+        // bring up the map; maybe we can't get there from here.  definitely out of sim.
+        llMapDestination(llGetRegionName(), check_posn, ZERO_VECTOR);
+        proclaim_arrival();
+///    }
+}
+
+// if the string "to_chew" looks like an offset vector, we return the calculated position.
+// otherwise we just convert the string to a list of vectors.
+list chewed_destination(string dests)
+{
+
+//hmmm: document this!!!
+//      as in, we support the offset format!
+
+    // look for our special start character for offsets.
+    if (is_prefix(dests, "o"))
+        return [ (vector)llDeleteSubString(dests, 0, find_substring(dests, "<") - 1) + llGetPos() ];
+
+//        if (DEBUGGING) log_it("decided for normal jaunt instead.");        
+    // jaunt to list of absolute coordinates.
+    return llParseString2List(dests, [VECTOR_SEPARATOR], []);
+}
+
+// sets the current destination to the vector at "which_index".
+select_destination(integer which_index)
+{
+    push_action_record(AQ_SELECT_DESTINATION, [which_index]);
+    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
+        wrap_parameters([OUR_COW_TAG, llList2String(global_names, which_index)]));
+}
+
+// processes the timer events from normal runtime.
+handle_normal_runtime_timer()
+{
+    if (!recon_started_yet) {
+        if (DEBUGGING) log_it("moving on to recon finally.");
+        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZ_CHILD_NOW,
+            wrap_parameters( [llGetInventoryName(INVENTORY_OBJECT, 1),
+                RECONNAISSANCE_TRIP, private_chat_channel,
+                "n",  // don't care about a particular name.
+                llGetListLength(global_names),
+                "n"  // no particular path.
+                ]));
+        recon_started_yet = TRUE;  // well, started really.                
+    }
+    llSetTimerEvent(0.0);  // stop coming here.
+}
+
+//////////////
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+///////////////
+
+// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
+integer valid_sim_value(float to_check)
+{
+    if (to_check < 0.0) return FALSE;
+    if (to_check >= 257.0) return FALSE;
+    return TRUE;
+}
+
+// returns TRUE if the "to_check" vector is a location outside of the current sim.
+integer outside_of_sim(vector to_check)
+{
+    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
+}
+
+// returns text for a floating point number, but includes only
+// two digits after the decimal point.
+string float_chop(float to_show)
+{
+    integer mant = llAbs(llRound(to_show * 100.0) / 100);
+    string neg_sign;
+    if (to_show < 0.0) neg_sign = "-";
+    string dec_s = (string)((llRound(to_show * 100.0) - mant * 100) / 100.0);
+    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
+    // strip off all trailing zeros.
+    while (llGetSubString(dec_s, -1, -1) == "0")
+        dec_s = llDeleteSubString(dec_s, -1, -1);
+    string to_return = neg_sign + (string)mant;
+    if (llStringLength(dec_s)) to_return += "." + dec_s;
+    return to_return;
+}
+
+// returns a prettier form for vector text, with chopped floats.
+string vector_chop(vector to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ">";
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{
+    string full_lower = llToLower(full_string);
+    return llSubStringIndex(full_lower, pattern);
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//////////////
+
+// default state scrounges for information in a notecard and looks for landmarks in
+// inventory to add as destinations.
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        if (DEBUGGING) log_it("=> default, mem=" + (string)llGetFreeMemory());
+        initialize_jaunter();
+    }
+
+    timer() {
+        // config loading timed out.
+        log_it("config timeout; resetting.");
+        llResetScript();
+    }
+    
+    // process the response from the noteworthy library.
+    link_message(integer which, integer num, string msg, key id) {
+        if (handle_link_message(which, num, msg, id)) {
+            state normal_runtime;
+        }
+    }
+    
+    on_rez(integer parm) { state default; }  // start-up from scratch.
+}
+
+// the normal state is pretty calm; the jaunter just sits there waiting for
+// an avatar who needs it to do something.
+state normal_runtime
+{
+    state_entry() {
+        if (DEBUGGING) log_it("=> normal");
+        init_normal_runtime();
+    }
+
+    listen(integer channel, string name, key id, string message) {
+        if (listen_to_voices(channel, name, id, message)) {
+            // we're ready to take off now.
+            state jaunting_now;
+        }
+    }
+
+    timer() { handle_normal_runtime_timer(); }
+
+    touch_end(integer total_number)
+    {
+        if (llDetectedLinkNumber(0) != llGetLinkNumber()) return;
+        touchy_feely();
+    }
+
+    changed(integer change) {
+        // always react to a change by resetting the label, in hopes we'll see
+        // the targeting arrow properly.
+        string destname = llList2String(global_names, current_target_index);
+        text_label_for_destination(destname);
+        // now do our 'real' activities for changes.
+        if (change & CHANGED_INVENTORY) {
+            log_it("inventory changed; restarting.");
+            llResetScript();
+        }
+        if (!(change & CHANGED_LINK)) return;  // don't care then.
+        if (llAvatarOnSitTarget() == NULL_KEY) return;  // there is no one sitting now.
+        state jaunting_now;  // sweet, we're off.
+    }
+        
+    // process the response from the menu library.
+    link_message(integer which, integer num, string msg, key id) {
+        handle_link_message(which, num, msg, id);
+    }
+
+    on_rez(integer parm) { state default; }  // start-up from scratch.
+}
+
+// once someone is trying to jump to a target, this state processes the request.
+state jaunting_now
+{
+    state_entry() {
+        if (DEBUGGING) log_it("=> jauntnow, posn=" + vector_chop(llGetPos()));
+        jaunt_responses_awaited = 0;  // nothing pending right now.
+        slackness_counter = 0;
+        if (conveyance_mode == AUTOREZ_JAUNTER) {
+            // we're going to create a kid, so we will not change state until we hear from it.
+            child_needs_setup = TRUE;
+            // give the person a vehicle to ride to the unsafe locale.  we assume the
+            // one way jaunter is the first inventory item.
+            llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZ_CHILD_NOW,
+                wrap_parameters([llGetInventoryName(INVENTORY_OBJECT, 0),
+                    ONE_WAY_TRIP, private_chat_channel,
+                    llList2String(global_names, current_target_index),
+                    llGetListLength(global_names),
+                    llDumpList2String(full_journey, VECTOR_SEPARATOR) ]));
+        } else {
+//            if (DEBUGGING) log_it("now going to first locat: " + (string)full_journey);
+            // patch the journey list for our most current location.
+            full_journey = [ vector_chop(llGetPos()) ] + llDeleteSubList(full_journey, 0, 0);
+
+            // most jaunters go to at least the first location...
+            request_jaunt(full_journey, TRUE);
+            eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
+            llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+        }
+    }
+
+    listen(integer channel, string name, key id, string message) {
+        listen_to_voices(channel, name, id, message);
+    }
+
+    timer() {
+        if (jaunt_responses_awaited || child_needs_setup) {
+            // we are not quite there yet.
+            if (check_for_timeout()) state normal_runtime;  // oops.
+            return;  // not time yet.
+        }
+        // we got to where we were going, maybe.
+        // now unseat the avatar.  this leaves her at the destination.
+        llUnSit(llAvatarOnSitTarget());
+        state arrived_at_target;
+    }
+
+    // process the response from the jaunting library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+
+    on_rez(integer parm) { state default; }  // start-up from scratch.
+}
+
+// this state is activated when the first jaunt is complete.
+state arrived_at_target
+{
+    state_entry() {
+        if (DEBUGGING) log_it("=> arv_targ, pos=" + vector_chop(llGetPos()));
+        // we are close enough; get back to work.
+        jaunt_responses_awaited = 0;  // nothing pending right now.
+        if ( ///(conveyance_mode != RECONNAISSANCE_TRIP) && 
+        (conveyance_mode != AUTOREZ_JAUNTER) )
+            llWhisper(0, "↣ " + llList2String(global_names, current_target_index));
+
+        // we've gotten where we were going.
+        proclaim_arrival();
+
+        // reverse direction and head back without rider.
+        eventual_destination = (vector)llList2String(full_journey, 0);
+        request_jaunt(full_journey, FALSE);
+        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+        slackness_counter = 0;
+    }
+
+    timer() {
+        if (jaunt_responses_awaited) {
+            // we are not quite there yet.
+            if (check_for_timeout()) state normal_runtime;  // oops.
+            return;  // not time yet.
+        }
+        if (!close_enough(eventual_destination))
+            log_it("far away, path okay?");
+        state normal_runtime;
+    }
+    
+    // process the response from the jaunting library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+
+    on_rez(integer parm) { state default; }  // start-up from scratch.
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunt_wik_rez_v86.3.txt b/huffware/huffotronic_jaunter_updater_v5.1/jaunt_wik_rez_v86.3.txt
deleted file mode 100755 (executable)
index f8273c1..0000000
+++ /dev/null
@@ -1,1205 +0,0 @@
-
-// huffware script: jaunt wik rez, by fred huffhines,  released under GPL license.
-//
-// this is a jaunter (teleporter) script with some useful and uncommon features.
-// it can work around certain types of complicated land permissions on neighboring land
-// that might otherwise lead to blocked jaunts.
-// the usage of "jaunt" for teleportation is inspired by the alfred bester novel, "the stars
-// my destination".  if you like science fiction and have not read this book, it is highly
-// recommended.
-// parts of this script are based on "Teleporter Script v 3.0 by Asira Sakai", from
-// the LSL wiki.
-//
-// use jaunt wik rez by placing a notecard in the inventory of your jaunter object.  the notecard
-// should start with "#jaunt" on the first line and then should have alternating lines of
-// (1) jaunt target (as a vector) and (2) readable target name, for example:
-//      #jaunt
-//      <23, 18, 92>
-//      gracy square
-//      <182, 32, 56>
-//      tourmaline palace
-//      <23, 18, 92>|<118, 19, 108>|<120, 33, 57>
-//      unblocked pathway, hurrah
-// note the last destination; the script also supports a list of intermediate destinations.
-// this feature can enable one to route a teleport around blocked lands by using waypoints
-// that are still accessible.  but since the current version of the script automatically
-// finds routes for most destinations, this is not needed very frequently.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-
-integer DEBUGGING = FALSE;
-    // make true to print diagnostic logging.
-
-// configurable options (set in notecard):
-
-integer SHOW_TEXT = TRUE;
-    // if true, then the jaunter will show a text label for the destination.
-    // this can be configured from the notecard with ":show_text=0" to turn off,
-    // or 1 to turn on.
-integer ADD_NAME = FALSE;
-    // if this is true, then the text shown will include the object's name.
-
-string TEXT_COLOR = "<0.3, 0.9, 0.7>";
-    // set float text color to a nice color.
-///hmmm: doesn't seem to be in the notecard yet!
-
-//////////////
-
-// the jaunter button pushing API.
-//////////////
-integer BUTTON_PUSHER_HUFFWARE_ID = 10029;
-    // a unique ID within the huffware system for this script.
-//////////////
-string BUTTON_PUSHED_ALERT = "#btnp";
-    // this event is generated when the button is pushed.  the number parameter will be
-    // the huffware id plus the reply distance.  the id parameter in the link message will
-    // contain the name of the button that was 
-string JAUNT_NEXT_BUTTON_NAME = "next";
-string JAUNT_MENU_BUTTON_NAME = "menu";
-
-//////////////
-    
-// requires the jaunt config API.
-//////////////
-// do not redefine these constants.
-integer JAUNT_CONFIGURATION_HUFFWARE_ID = 10022;
-    // the unique id within the huffware system for this script's commands.
-    // it's used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-// commands available from the jaunt config library:
-string LOAD_ALL_CONFIGURATIONS = "#rdcfg#";
-    // this starts the process of loading jaunt destinations from the notecards and
-    // landmarks that we find in the object.  the parms are: private channel
-    // and conveyance mode.
-string JAUNT_CFG_DATA_EVENT = "#yodata#";
-    // this event is generated from this script back to the caller.  when we have some
-    // landmark data or configuration information, it's passed back in chunks.  the
-    // deluge of pieces will continue until the JAUNT_CFG_EOF event is passed.  the
-    // parameters include packed destination name and vector pairs (which form 2 elements
-    // in the list) and packed config variable definitions (where config items start
-    // with a colon, and the definition is only one element in the list).
-string JAUNT_CFG_EOF = "#done#";
-    // sent after all valid configuration items that we could find were processed.
-//
-//////////////
-
-// requires jaunting library API.
-//////////////
-// do not redefine these constants.
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-//////////////
-// commands available via the jaunting library:
-string FULL_STOP_COMMAND = "#fullstop#";
-    // command used to bring object to a halt.
-string JAUNT_LIST_COMMAND = "#jauntlist#";
-    // like regular jaunt, but expects a string in jaunt notecard format with vectors.
-    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
-//
-//////////////
-
-// requires menutini API.
-//////////////
-// do not redefine these constants.
-integer MENUTINI_HUFFWARE_ID = 10009;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string SHOW_MENU_COMMAND = "#menu#";
-    // the command that tells menutini to show a menu defined by parameters
-    // that are passed along.  these must be: the menu name, the menu's title
-    // (which is really the info to show as content in the main box of the menu),
-    // the wrapped list of commands to show as menu buttons, the menu system
-    // channel's for listening, and the key to listen to.
-
-// requires data cow library API.
-//////////////
-// do not redefine these constants.
-integer DATA_COW_HUFFWARE_ID = 10017;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-//////////////
-string RESET_LIST_COMMAND = "reset_L";
-    // flushes out the currently held list.  does not send a reply.
-string ADD_ITEM_COMMAND = "add_I";
-    // adds items to the list.  this is a list of pairs of name/value, where the name is
-    // how the item will be looked up from the list, and the value is the contents to be stored.
-    // this command has no reply.
-string GET_COW_LENGTH = "get_Lc";
-    // returns a single integer which is the length of the cow's list currently.
-//string REMOVE_ITEM_COMMAND = "rm_I";
-    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
-    // this command also has no reply.
-//string GET_ITEM_COMMAND = "get_I";
-    // retrieves the item's contents for a given name.  first parm is the name.  if there
-    // are other parameters, then they are taken as other items to return also.
-    // the return data will be pairs of <name, entry> for each of the names in the request.
-    // if the data was not located, then the entry will be empty.
-string TAGGED_GET_ITEM_COMMAND = "get_T";
-    // like get item, except the first parameter is an identifier that the caller wants to
-    // use to tag this request.  the other parameters are still taken as names.  the response
-    // will contain the tag as the first item, then the <name, entry> pairs that were found.
-
-//////////////
-
-// requires click action API...
-//////////////
-integer CHANGE_CLICK_ACTION_HUFFWARE_ID = 10024;
-    // a unique ID within the huffware system for this script.
-// the API only supports the service number; there are no commands to pass in the "msg"
-// parameter.  the id does accept a parameter, which is the type of click action to begin
-// using for this prim.
-//////////////
-
-// the API for this library script to be used in other scripts.
-//////////////
-// do not redefine these constants.
-integer JAUNT_REZOLATOR_HUFFWARE_ID = 10025;
-    // the unique id within the huffware system for this script's commands.
-    // it's used in llMessageLinked as the num parameter.
-//////////////
-// commands available from the library:
-string RESET_REZOLATOR = "#reset";
-    // tells the script to stop any previous efforts to rez children.
-string REZ_CHILD_NOW = "#rezkd#";
-    // requests this script to create a new child object.  this requires several
-    // parameters to succeed: 1) object to rez, 2) conveyance mode for the rezzed object
-    // to implement, 3) the chat channel to listen for and speak to new child on,
-    // 4) the destination name for where the child should go, 5) a count of the full
-    // set of known destinations, 6) the target where the jaunt should arrive at.
-//////////////
-// events generated by the library:
-string REZOLATOR_EVENT_REZZED_CHILD = "#donekd";
-    // an event generated for a previous rez child request.  this lets the caller know that
-    // the child has been created and told what to do.  the single parameter is where the
-    // jaunter has been rezzed.
-string REZOLATOR_EVENT_RECON_FINISHED = "#rzcnfn";
-    // an event generated when the recon process has concluded.  this includes parms:
-    // number of good destinations.
-//
-//////////////
-
-// important constants used internally...  these should not be changed willy nilly.
-
-////////////// jaunt base API
-
-// the following constants define how the script should behave (i.e., its conveyance mode).
-// TWO_WAY_TRIP: the script jaunts using the current target vectors to get somewhere
-//   and then takes the same pathway back, but in reverse order.
-// AUTOREZ_JAUNTER: the script rezzes the first regular object in its inventory next to
-//   the root telehub.  that object is loaded with the destination notecard and this script.
-//   the rezzed object can then be used for the next few minutes to jaunt to the selected
-//   destination.  the temporary object will use the ONE_WAY_TRIP mode.
-// ONE_WAY_TRIP: the object containing this script will take the user to a particular
-//   destination, but the object does not survive the trip.  it self-destructs after
-//   reaching the destination.  this mode is used in conjunction with the AUTOREZ_JAUNTER
-//   mode and should generally never be used on its own.
-// RECONNAISSANCE_TRIP: a survey run to test out a particular path to get to a
-//   destination.
-integer TWO_WAY_TRIP = 1;
-integer AUTOREZ_JAUNTER = 2;
-integer ONE_WAY_TRIP = 3;
-integer RECONNAISSANCE_TRIP = 4;
-
-// values used to represent different stages of verification.
-integer VERIFY_UNTESTED = -3;  // don't know destinations state yet.
-integer VERIFY_SAFE = -4;  // the destination last tested safe.
-integer VERIFY_UNSAFE_SO_FAR = -5;  // this cannot be done with simple jaunt.
-integer VERIFY_UNSAFE_DECIDED = -6;  // this means the destination seems intractable.
-
-integer MAXIMUM_PRIV_CHAN = 90000;
-    // the largest amount we will ever subtract from the tricky parms in order to
-    // tell the sub-jaunter which channel to listen on.
-
-string VECTOR_SEPARATOR = "|";
-    // how we separate components of vectors from each other.
-string DB_SEPARATOR = "``";  // separating items in lists.
-
-////////////// end jaunt base API
-
-integer MAX_DEST_NAME = 24;  // the longest name that we store.
-
-float NORMAL_TIMER_PERIOD = 1.0;  // our normal timer rate.
-
-string RESET_COMMAND = "jreset";  // forget everything and start over.
-string SHOW_COMMAND = "show";  // describe the known destinations.
-string RECON_COMMAND = "recon";  // tells the jaunter to run reconnaissance on destinations.
-
-float POSITION_CHECKING_INTERVAL = 0.11;
-    // how frequently the waiting for arrival state will check where we are.
-
-integer MAXIMUM_SLACKNESS = 108;
-    // how many timer hits we'll allow before reverting to the default state.
-
-integer FREE_MEM_REQUIRED = 1600;
-    // we need at least this much memory before adding new targets.
-
-// somewhere between two and 10 minutes (default) will elapse before first recon testing.
-float MIN_RECON_SNOOZE = 120;
-float MAX_RECON_SNOOZE = 1200;
-
-// the actions that can be held in the action queue.
-integer AQ_SHOW_DEST_RECORD = 23;  // a record to be shown to the user.
-integer AQ_FINISH_SHOW_DESTS = 24;  // last record in a jaunt destinations list.
-integer AQ_CLICK_ACTION_REQUEST = 25;  // the response should set our click action.
-integer AQ_SELECT_DESTINATION = 27;  // the user has chosen a different destination.
-integer AQ_DONE_CONFIGURING = 28;  // the last step of the configuration process has finished.
-
-string OUR_COW_TAG = "jwkrz_dc";  // unique id for this script to talk to the data cow with.
-
-//////////////
-
-// global variables.
-
-integer private_chat_channel;  // where sub-jaunters communicate with root.
-integer conveyance_mode;  /// = TWO_WAY_TRIP;
-    // default is a standard two way trip, there and back again.  note that the object
-    // will fail to return if any lands in between are blocking object entry.  those
-    // situations should use an auto-rez jaunter, which is specified by prefixing the
-    // target vectors with AR.
-integer last_verification_state;  // the verification state of the last destination we asked for.
-string last_pathway;  // similar, but the last pathway we heard.
-integer current_target_index;  // the location in the list that we would currently jaunt to.
-
-integer good_destinations;  // computed during the recon process.
-
-// jaunter target configuration...
-list global_names;  // the names for each destination.
-
-// jaunt trip variables...
-vector eventual_destination;  // where we're headed, if we're headed anywhere.
-integer slackness_counter;  // snoozes had while waiting for destination.
-list full_journey;  // the full pathway we expect to jaunt on.
-integer jaunt_responses_awaited;  // number of pending jumps in progress.
-
-// root jaunter variables...
-integer child_needs_setup;
-    // true when a child has been rezzed and still needs to be filled with the script.
-
-integer recon_started_yet = FALSE;
-    // true if we've finished running through the reconnaissance process yet.
-
-//////////////
-
-// makes our click action change to the type requested, and sends the request
-// out to all our sub-prims also.
-set_click_action(integer action)
-{
-    llSetClickAction(action);
-    // secret message to other prims to change click action.
-    llMessageLinked(LINK_SET, CHANGE_CLICK_ACTION_HUFFWARE_ID, "", (string)action);
-}
-
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-
-// show the list of options for someone who used the click-hold feature.
-show_jaunt_menu(key last_toucher)
-{
-    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
-        "jm" + HUFFWARE_PARM_SEPARATOR
-        + "Jaunt to..." + HUFFWARE_PARM_SEPARATOR
-        + wrap_item_list(global_names)
-        + HUFFWARE_PARM_SEPARATOR
-        + (string)random_channel() + HUFFWARE_PARM_SEPARATOR
-        + (string)last_toucher);
-}
-
-// respond to the user's choice.
-react_to_menu(string which_choice)
-{
-    integer indy;
-    // find the specified destination and select it.
-    indy = llListFindList(global_names, [which_choice]);
-    if (indy >= 0) {
-        current_target_index = indy;
-        select_destination(current_target_index);
-    }
-}
-
-// asks the jaunting library to take us to the target using a list of waypoints.
-request_jaunt(list journey, integer forwards)
-{
-    // ask for a jump.
-    jaunt_responses_awaited++;
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_LIST_COMMAND,
-        wrap_item_list(journey) + HUFFWARE_PARM_SEPARATOR + (string)forwards);
-    // stops the jaunter in its tracks.
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, FULL_STOP_COMMAND, ""); 
-}
-
-// this function returns TRUE if we are close enough to the "destination".
-integer close_enough(vector destination)
-{
-    float PROXIMITY_REQUIRED = 0.1;
-        // how close we must be to the target location to call it done.
-        // matches current jaunting library proximity.
-    return (llVecDist(llGetPos(), destination) <= PROXIMITY_REQUIRED);
-}
-
-// returns appropriate sit text for our current jaunt mode.
-string sit_text()
-{
-    if (conveyance_mode == AUTOREZ_JAUNTER) return "Rez Ride";
-    return "Jaunt";
-}
-
-// plops a new destination on the end of the lists.
-add_destination(string name, string path, integer verif)
-{
-//    if (DEBUGGING) log_it("adding " + name + " with path " + path);
-    global_names += [ name ];
-    // send our new information to the data cow.  we store the information encoded as
-    // two separated items, where the first element is the destination and the second
-    // is the verification state.
-    string new_entry = wrap_item_list([path, verif]);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, ADD_ITEM_COMMAND,
-        wrap_parameters([name, new_entry]));
-}
-
-// sets up the initial state, if this script has just started, or it
-// cleans up the state, if the script was already running.
-initialize_jaunter()
-{
-    llSetTimerEvent(0.0);  // cancel any existing timers.
-
-    // reset all the important variables.
-    global_names = [];
-    current_target_index = 0;
-    good_destinations = 0;
-
-    llSitTarget(<0, 0, 0.1>, ZERO_ROTATION);
-        // set a rudimentary sit target or opensim won't give us our changed events.
-    // load up an arrival sound if any exist.
-    if (llGetInventoryNumber(INVENTORY_SOUND))
-        llPreloadSound(llGetInventoryName(INVENTORY_SOUND, 0));
-    // reset the parallel processing scripts since we've restarted.
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, RESET_LIST_COMMAND, "");
-    llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, RESET_REZOLATOR, "");
-    
-    // see if we can load our configuration from notecards and landmarks.
-    // we pick a private channel that fits in between our rez parm ranges.
-    private_chat_channel = (integer)randomize_within_range(-MAXIMUM_PRIV_CHAN, -1, FALSE);
-    // request that all the config get loaded up.
-    llMessageLinked(LINK_THIS, JAUNT_CONFIGURATION_HUFFWARE_ID, LOAD_ALL_CONFIGURATIONS,
-         wrap_parameters([private_chat_channel, conveyance_mode]));
-    // during a normal trip, we will make sure the notecard reading doesn't stall.
-    // the recon and one way jaunters don't need this; they're temporary.
-    // we allow this number of seconds before notecard reader is awol.
-    llSetTimerEvent(94);
-
-    conveyance_mode = TWO_WAY_TRIP;  // default init in opensim friendly way.
-
-    // set up some of the object properties...
-    string msg;
-    if (SHOW_TEXT) msg = "?...";
-    llSetText(msg, (vector)TEXT_COLOR, 1.0);  // initial floating text for jaunter.
-    llSetSitText(sit_text());  // change to the proper text for our mode.
-}
-
-init_normal_runtime()
-{
-    child_needs_setup = FALSE;
-    // listen to the general public for commands.
-    llListen(0, "", NULL_KEY, "");
-    // set up a root jaunter.
-    recon_started_yet = FALSE;        
-    llSetTimerEvent(randomize_within_range(MIN_RECON_SNOOZE, MAX_RECON_SNOOZE, FALSE));
-}
-
-// signal that we are where we were going.
-proclaim_arrival()
-{
-    if (conveyance_mode == TWO_WAY_TRIP) {
-        // sing a little song, if there's a sound to use.
-        if (llGetInventoryNumber(INVENTORY_SOUND))
-            llTriggerSound(llGetInventoryName(INVENTORY_SOUND, 0), 1.0);
-    }
-}
-
-string verification_name(integer enumtype)
-{
-    if (enumtype == VERIFY_SAFE) return "ok";
-    else if (enumtype == VERIFY_UNSAFE_SO_FAR) return "uhh";
-    else if (enumtype == VERIFY_UNSAFE_DECIDED) return "far";
-    // catch-all, including untested.
-    return "?";
-}
-
-// returns true if the slackness counter awaiting things has elapsed.
-integer check_for_timeout()
-{
-    if (slackness_counter++ > MAXIMUM_SLACKNESS) {
-        // go back to the main state.  we took too long.
-        log_it("timed out!");
-        llUnSit(llAvatarOnSitTarget());  // don't hang onto the avatar for this error.
-        llSetTimerEvent(0.0);
-        return TRUE;
-    }
-    return FALSE;
-}
-
-//////////////
-
-// action queue for postponed activities.  the first field held in a list item here
-// is an integer action code.  the format of the remaining parameters is up to the
-// caller, and they can be used as the final parameters for when the queued action
-// gets handled.
-list action_queue;
-
-// looks at the action code at the head of the queue without removing the action.
-integer peek_action_code()
-{
-    list fields = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
-    return extract_action_code(fields);
-}
-
-// extracts the action code from a retrieved list.
-integer extract_action_code(list to_parse) { return llList2Integer(to_parse, 0); }
-
-// removes the current head of the action queue and returns it.
-list pop_action_record()
-{
-    if (llGetListLength(action_queue) == 0) {
-//        if (DEBUGGING) log_it("failure in action q: no entries.");
-        return [];
-    }
-    list top_action = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
-    action_queue = llDeleteSubList(action_queue, 0, 0);
-    jaunt_responses_awaited--;  // one less thing to wait for.
-    return top_action;
-}
-
-// adds a new action to the end of the action queue.
-push_action_record(integer action, list added_parms)
-{
-    action_queue += [ wrap_parameters([action] + added_parms) ];
-    jaunt_responses_awaited++;  // add one counter to our pending responses.
-}
-
-//////////////
-
-string show_buffer;  // used by the destination list showing code below.
-
-// requests a dump of all the jaunt destinations so we can show them to the user.
-get_destination_records()
-{
-    show_buffer = "[mem " + (string)llGetFreeMemory() + "]";  // set the first line in the output.
-    
-    integer indy;
-    for (indy = 0; indy < llGetListLength(global_names); indy++) {
-        string curr = llList2String(global_names, indy);
-        // ask for this destination record.
-        llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-            wrap_parameters([OUR_COW_TAG, curr]));
-        integer action = AQ_SHOW_DEST_RECORD;
-        if (indy == llGetListLength(global_names) - 1) {
-            // if it's the last item, make sure we signal that.
-            action = AQ_FINISH_SHOW_DESTS;
-        }
-        push_action_record(action, []);
-    }
-}
-
-// displays the list of destinations in normal chat that the data cow is handing us.
-show_destination_record(string loc_name, string pathway, integer verif, integer action)
-{
-    integer MAX_CHAT = 512;  // the largest we let the buffer get before saying it.
-    show_buffer += "   " + loc_name + " ("
-        + verification_name(verif) + ") â†£ " + pathway;
-    // if we're done, add a note about quality of targets.
-    if (action == AQ_FINISH_SHOW_DESTS) {
-        show_buffer += "\n  (" + (string)good_destinations + " safe & "
-            + (string)(llGetListLength(global_names) - good_destinations)
-            + " tough ones)";
-    }
-        
-    // if we're done or if the string gets too big, print and reset it.
-    if ( (action == AQ_FINISH_SHOW_DESTS) || (llStringLength(show_buffer) >= MAX_CHAT) ) {
-        llWhisper(0, show_buffer);
-        show_buffer = "";
-    }
-}
-
-// returns the value of a boolean variable definition.
-integer parse_bool_def(string def)
-{ return !(llGetSubString(def, find_substring(def, "=") + 1, -1) == "0"); }
-
-// processes a configuration option from the notecard.
-handle_config_item(string item)
-{
-    item = llGetSubString(item, 1, -1);  // chop the command signifier character.
-    if (is_prefix(item, "show_text")) {
-        // they are controlling whether to show the text label or not.
-        SHOW_TEXT = parse_bool_def(item);
-    } else if (is_prefix(item, "add_name")) {
-        ADD_NAME = parse_bool_def(item);
-    }
-}
-
-// processes items coming from the configuration library.
-consume_configuration_items(string msg, string id)
-{
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    integer mem_okay = llGetFreeMemory() >= FREE_MEM_REQUIRED;  // false if we're low on memory.
-    if (!mem_okay) return;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(parms); indy += 2) {
-        string name = llList2String(parms, indy);
-        if (is_prefix(name, ":")) {
-            handle_config_item(name);
-            indy--;  // skip back so we continue looking for destinations.
-        } else {
-            // this should be a normal pair of destination vector and name.
-            integer verif_state = VERIFY_UNTESTED;
-            // check if it's a wacky location.
-            string map_coord = llList2String(parms, indy + 1);
-            list chewed = chewed_destination(map_coord);
-            if (outside_of_sim((vector)llList2String(chewed, 0))) {
-                if (DEBUGGING) log_it("ruled map_coor " + (string)map_coord + " out of sim.");
-                // make sure we consider the tp location "unsafe", since we can't run in-sim
-                // reconnaissance against it.  also, we must postpone marking it until
-                // the destination is listed, given current implementation.
-                verif_state = VERIFY_UNSAFE_DECIDED;
-            }
-            add_destination(name, llList2String(parms, indy + 1), verif_state);
-        }
-    }
-}
-
-// handles responses about our list coming back from the data cow.
-integer answer_to_the_cow(string msg, string id, list parms)
-{
-    string tag = llList2String(parms, 0);
-    if (tag != OUR_COW_TAG) return FALSE;  // was not for us.
-    parms = llDeleteSubList(parms, 0, 0);  // trim out the tag.
-    list action_record = pop_action_record();
-    integer actyo = extract_action_code(action_record);
-    list split = llParseString2List(llList2String(parms, 1), [HUFFWARE_ITEM_SEPARATOR], []);
-    if ( (actyo == AQ_SHOW_DEST_RECORD) || (actyo == AQ_FINISH_SHOW_DESTS) ) {
-        show_destination_record(llList2String(parms, 0), llList2String(split, 0),
-            llList2Integer(split, 1), actyo);
-    } else if (actyo == AQ_CLICK_ACTION_REQUEST) {
-        // make sure we're in the right mode for clicking based on how
-        // many destinations we have.  if there's only one, we might as
-        // well make this jaunter just go there.
-        // note: just discovered that we cannot set the click action if the jaunter
-        // is multiple prims.  that's totally fubar.  it means we cannot correctly
-        // set the jaunter main body to show 'sit' as the option, even when jaunting
-        // directly to the destination is possible.  freaking lindens.  maybe osgrid
-        // will fix this someday.
-        if (llGetListLength(global_names) == 1) {
-            if (llList2Integer(split, 1) != VERIFY_UNSAFE_DECIDED)
-                set_click_action(CLICK_ACTION_SIT);
-            else
-                // we have a non-local jaunter, so set up for map clicking.
-                set_click_action(CLICK_ACTION_TOUCH);
-        } else set_click_action(CLICK_ACTION_TOUCH);
-    } else if (actyo == AQ_SELECT_DESTINATION) {
-        integer verif = llList2Integer(split, 1);
-        // we only switch conveyance mode if we have not been told to
-        // do the one-way trip or recon.
-        if (verif == VERIFY_SAFE) conveyance_mode = TWO_WAY_TRIP;
-        else conveyance_mode = AUTOREZ_JAUNTER;
-        llSetSitText(sit_text());  // change to the proper text for our mode.
-        full_journey = [ vector_chop(llGetPos()) ] + chewed_destination(llList2String(split, 0));
-        integer last_selecting_index = llList2Integer(action_record, 1);
-        string destname = llList2String(global_names, last_selecting_index);
-        llWhisper(0, "Next stop: " + destname);
-        text_label_for_destination(destname);
-        last_verification_state = verif;
-        last_pathway = llList2String(split, 0);
-    } else if (actyo == AQ_DONE_CONFIGURING) {
-        // done with notecard reading, but we still need reconnaissance.
-        // we'll do that in the normal runtime state.
-        return TRUE;        
-    }
-    return FALSE;  // unknown request or a fall-through.
-}
-
-// asks the data cow for our current set of configured destinations and their
-// requisite click actions.
-request_destinations()
-{
-    push_action_record(AQ_CLICK_ACTION_REQUEST, []);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-        wrap_parameters([OUR_COW_TAG, llList2String(global_names, 0)]));
-}
-
-// processes link messages received from support libraries.
-integer handle_link_message(integer which, integer num, string msg, string id)
-{
-    // is it an answer about our configuration?
-    if (num == JAUNT_CONFIGURATION_HUFFWARE_ID + REPLY_DISTANCE) {
-        if (msg == JAUNT_CFG_DATA_EVENT) {
-            // eat these configuration items we were given.
-            consume_configuration_items(msg, id);
-        } else if (msg == JAUNT_CFG_EOF) {
-            // we have finished up on the configuration.
-            completed_configuration();
-        }
-        return FALSE;
-    }
-    
-    // is it a jaunting library response?
-    if (num == JAUNT_HUFFWARE_ID + REPLY_DISTANCE) {
-        jaunt_responses_awaited--;  // one less response being awaited.
-        if (jaunt_responses_awaited < 0) {
-            if (DEBUGGING) log_it("error: j-rsp-awtd<0");
-            jaunt_responses_awaited = 0;
-        }
-        return FALSE;
-    }
-    
-    // is it an event from the rezolator script?
-    if (num == JAUNT_REZOLATOR_HUFFWARE_ID + REPLY_DISTANCE) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        if (msg == REZOLATOR_EVENT_REZZED_CHILD) {
-            // we know the child is ready for us now.
-            child_needs_setup = FALSE;
-//            if (DEBUGGING) log_it("setting journey to rez place " + vector_chop(llGetPos()));
-            full_journey = [ vector_chop(llGetPos()), llList2String(parms, 0) ];
-            if (DEBUGGING) log_it("heard kid is ready, helping.");
-            request_jaunt(full_journey, TRUE);
-            eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
-            llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-        } else if (msg == REZOLATOR_EVENT_RECON_FINISHED) {
-            good_destinations = llList2Integer(parms, 0);
-            if (DEBUGGING) log_it("recon finished, total=" + llGetListLength(global_names) + " good=" + good_destinations);
-            request_destinations();
-            select_destination(current_target_index);
-        }
-        return FALSE;
-    }
-
-    // is this a menu response from the user?
-    if (num == MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) {
-        // all we care about in our parms is the choice made.
-        react_to_menu(llList2String(llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []), 1));
-        return FALSE;
-    }
-    // or maybe it's a piece of data from the data cow.
-    if (num == DATA_COW_HUFFWARE_ID + REPLY_DISTANCE) {
-        return answer_to_the_cow(msg, id, llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []));
-    }
-    // perhaps it's a click on a button.
-    if (num == BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE) {
-        if (msg == BUTTON_PUSHED_ALERT) {
-            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-            if (llList2String(parms, 0) == JAUNT_NEXT_BUTTON_NAME) {
-                select_next_destination();
-            } else if (llList2String(parms, 0) == JAUNT_MENU_BUTTON_NAME) {
-                show_jaunt_menu(llList2String(parms, 1));
-            }
-        }
-    }
-
-    return FALSE;
-}
-
-// make some noise about getting configured right.
-completed_configuration()
-{
-    current_target_index = 0;  // set proper index.    
-    get_destination_records();
-
-    // set up the first destination.
-    select_destination(current_target_index);
-
-    // schedule the request asking how many destinations there are.
-    request_destinations();
-/*    push_action_record(AQ_CLICK_ACTION_REQUEST, []);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-        wrap_parameters([OUR_COW_TAG, llList2String(global_names, 0)]));*/
-
-    // add an item in the queue to actually begin jaunt services.
-    push_action_record(AQ_DONE_CONFIGURING, []);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-            wrap_parameters([OUR_COW_TAG, llList2String(global_names, 0)]));
-}
-
-// process what we hear in open chat and on our special channels.
-// this function should always return FALSE unless it's been given enough info
-// to enter a new state, in which case it should return true.
-integer listen_to_voices(integer channel, string name, key id, string message)
-{
-    if (channel == 0) {
-        // provide common command handling.
-        if (message == SHOW_COMMAND) {
-            // anyone can use this command.
-            get_destination_records();
-            return FALSE;
-        }
-        // the rest of the commands only listen to the owner.
-        if (id != llGetOwner()) return FALSE;
-        if (message == RESET_COMMAND) llResetScript();
-        else if (message == RECON_COMMAND) {
-            // if they want a recon, we'll do it right away.
-            recon_started_yet = FALSE;
-            // we want to reset the rezolator's state, in case it had done this before.
-            llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, RESET_REZOLATOR, "");
-            llSetTimerEvent(0.4);
-        }
-        return FALSE;
-    }
-
-    return FALSE;  // we do not want to go to next state; stay in current one.
-}
-
-// shows our next target for jaunting above the object.
-text_label_for_destination(string target)
-{
-    string msg;
-    if (SHOW_TEXT) {
-        if (ADD_NAME) msg += llGetObjectName() + ":\n";
-        msg += "↣ " + target;
-    }
-    llSetText(msg, (vector)TEXT_COLOR, 1.0);
-}
-
-select_next_destination()
-{
-    // picks the next place in the list for the destination, or wraps around.
-    current_target_index++;
-    if (current_target_index >= llGetListLength(global_names))
-        current_target_index = 0;
-    select_destination(current_target_index);
-}
-        
-touchy_feely()
-{
-    // check the safety of the target and show the map if the conditions are right.
-    vector check_posn = (vector)llList2String(chewed_destination(last_pathway), 0);
-///    if (outside_of_sim(check_posn)) {
-    /////old && (llGetListLength(global_names) == 1) ) {
-        // bring up the map; maybe we can't get there from here.  definitely out of sim.
-        llMapDestination(llGetRegionName(), check_posn, ZERO_VECTOR);
-        proclaim_arrival();
-///    }
-}
-
-// if the string "to_chew" looks like an offset vector, we return the calculated position.
-// otherwise we just convert the string to a list of vectors.
-list chewed_destination(string dests)
-{
-
-//hmmm: document this!!!
-//      as in, we support the offset format!
-
-    // look for our special start character for offsets.
-    if (is_prefix(dests, "o"))
-        return [ (vector)llDeleteSubString(dests, 0, find_substring(dests, "<") - 1) + llGetPos() ];
-
-//        if (DEBUGGING) log_it("decided for normal jaunt instead.");        
-    // jaunt to list of absolute coordinates.
-    return llParseString2List(dests, [VECTOR_SEPARATOR], []);
-}
-
-// sets the current destination to the vector at "which_index".
-select_destination(integer which_index)
-{
-    push_action_record(AQ_SELECT_DESTINATION, [which_index]);
-    llMessageLinked(LINK_THIS, DATA_COW_HUFFWARE_ID, TAGGED_GET_ITEM_COMMAND,
-        wrap_parameters([OUR_COW_TAG, llList2String(global_names, which_index)]));
-}
-
-// processes the timer events from normal runtime.
-handle_normal_runtime_timer()
-{
-    if (!recon_started_yet) {
-        if (DEBUGGING) log_it("moving on to recon finally.");
-        llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZ_CHILD_NOW,
-            wrap_parameters( [llGetInventoryName(INVENTORY_OBJECT, 1),
-                RECONNAISSANCE_TRIP, private_chat_channel,
-                "n",  // don't care about a particular name.
-                llGetListLength(global_names),
-                "n"  // no particular path.
-                ]));
-        recon_started_yet = TRUE;  // well, started really.                
-    }
-    llSetTimerEvent(0.0);  // stop coming here.
-}
-
-//////////////
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-///////////////
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-// returns TRUE if the "to_check" vector is a location outside of the current sim.
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-// returns text for a floating point number, but includes only
-// two digits after the decimal point.
-string float_chop(float to_show)
-{
-    integer mant = llAbs(llRound(to_show * 100.0) / 100);
-    string neg_sign;
-    if (to_show < 0.0) neg_sign = "-";
-    string dec_s = (string)((llRound(to_show * 100.0) - mant * 100) / 100.0);
-    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
-    // strip off all trailing zeros.
-    while (llGetSubString(dec_s, -1, -1) == "0")
-        dec_s = llDeleteSubString(dec_s, -1, -1);
-    string to_return = neg_sign + (string)mant;
-    if (llStringLength(dec_s)) to_return += "." + dec_s;
-    return to_return;
-}
-
-// returns a prettier form for vector text, with chopped floats.
-string vector_chop(vector to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ">";
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{
-    string full_lower = llToLower(full_string);
-    return llSubStringIndex(full_lower, pattern);
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//////////////
-
-// default state scrounges for information in a notecard and looks for landmarks in
-// inventory to add as destinations.
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        if (DEBUGGING) log_it("=> default, mem=" + (string)llGetFreeMemory());
-        initialize_jaunter();
-    }
-
-    timer() {
-        // config loading timed out.
-        log_it("config timeout; resetting.");
-        llResetScript();
-    }
-    
-    // process the response from the noteworthy library.
-    link_message(integer which, integer num, string msg, key id) {
-        if (handle_link_message(which, num, msg, id)) {
-            state normal_runtime;
-        }
-    }
-    
-    on_rez(integer parm) { state default; }  // start-up from scratch.
-}
-
-// the normal state is pretty calm; the jaunter just sits there waiting for
-// an avatar who needs it to do something.
-state normal_runtime
-{
-    state_entry() {
-        if (DEBUGGING) log_it("=> normal");
-        init_normal_runtime();
-    }
-
-    listen(integer channel, string name, key id, string message) {
-        if (listen_to_voices(channel, name, id, message)) {
-            // we're ready to take off now.
-            state jaunting_now;
-        }
-    }
-
-    timer() { handle_normal_runtime_timer(); }
-
-    touch_end(integer total_number)
-    {
-        if (llDetectedLinkNumber(0) != llGetLinkNumber()) return;
-        touchy_feely();
-    }
-
-    changed(integer change) {
-        // always react to a change by resetting the label, in hopes we'll see
-        // the targeting arrow properly.
-        string destname = llList2String(global_names, current_target_index);
-        text_label_for_destination(destname);
-        // now do our 'real' activities for changes.
-        if (change & CHANGED_INVENTORY) {
-            log_it("inventory changed; restarting.");
-            llResetScript();
-        }
-        if (!(change & CHANGED_LINK)) return;  // don't care then.
-        if (llAvatarOnSitTarget() == NULL_KEY) return;  // there is no one sitting now.
-        state jaunting_now;  // sweet, we're off.
-    }
-        
-    // process the response from the menu library.
-    link_message(integer which, integer num, string msg, key id) {
-        handle_link_message(which, num, msg, id);
-    }
-
-    on_rez(integer parm) { state default; }  // start-up from scratch.
-}
-
-// once someone is trying to jump to a target, this state processes the request.
-state jaunting_now
-{
-    state_entry() {
-        if (DEBUGGING) log_it("=> jauntnow, posn=" + vector_chop(llGetPos()));
-        jaunt_responses_awaited = 0;  // nothing pending right now.
-        slackness_counter = 0;
-        if (conveyance_mode == AUTOREZ_JAUNTER) {
-            // we're going to create a kid, so we will not change state until we hear from it.
-            child_needs_setup = TRUE;
-            // give the person a vehicle to ride to the unsafe locale.  we assume the
-            // one way jaunter is the first inventory item.
-            llMessageLinked(LINK_THIS, JAUNT_REZOLATOR_HUFFWARE_ID, REZ_CHILD_NOW,
-                wrap_parameters([llGetInventoryName(INVENTORY_OBJECT, 0),
-                    ONE_WAY_TRIP, private_chat_channel,
-                    llList2String(global_names, current_target_index),
-                    llGetListLength(global_names),
-                    llDumpList2String(full_journey, VECTOR_SEPARATOR) ]));
-        } else {
-//            if (DEBUGGING) log_it("now going to first locat: " + (string)full_journey);
-            // patch the journey list for our most current location.
-            full_journey = [ vector_chop(llGetPos()) ] + llDeleteSubList(full_journey, 0, 0);
-
-            // most jaunters go to at least the first location...
-            request_jaunt(full_journey, TRUE);
-            eventual_destination = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
-            llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-        }
-    }
-
-    listen(integer channel, string name, key id, string message) {
-        listen_to_voices(channel, name, id, message);
-    }
-
-    timer() {
-        if (jaunt_responses_awaited || child_needs_setup) {
-            // we are not quite there yet.
-            if (check_for_timeout()) state normal_runtime;  // oops.
-            return;  // not time yet.
-        }
-        // we got to where we were going, maybe.
-        // now unseat the avatar.  this leaves her at the destination.
-        llUnSit(llAvatarOnSitTarget());
-        state arrived_at_target;
-    }
-
-    // process the response from the jaunting library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-
-    on_rez(integer parm) { state default; }  // start-up from scratch.
-}
-
-// this state is activated when the first jaunt is complete.
-state arrived_at_target
-{
-    state_entry() {
-        if (DEBUGGING) log_it("=> arv_targ, pos=" + vector_chop(llGetPos()));
-        // we are close enough; get back to work.
-        jaunt_responses_awaited = 0;  // nothing pending right now.
-        if ( ///(conveyance_mode != RECONNAISSANCE_TRIP) && 
-        (conveyance_mode != AUTOREZ_JAUNTER) )
-            llWhisper(0, "↣ " + llList2String(global_names, current_target_index));
-
-        // we've gotten where we were going.
-        proclaim_arrival();
-
-        // reverse direction and head back without rider.
-        eventual_destination = (vector)llList2String(full_journey, 0);
-        request_jaunt(full_journey, FALSE);
-        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-        slackness_counter = 0;
-    }
-
-    timer() {
-        if (jaunt_responses_awaited) {
-            // we are not quite there yet.
-            if (check_for_timeout()) state normal_runtime;  // oops.
-            return;  // not time yet.
-        }
-        if (!close_enough(eventual_destination))
-            log_it("far away, path okay?");
-        state normal_runtime;
-    }
-    
-    // process the response from the jaunting library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-
-    on_rez(integer parm) { state default; }  // start-up from scratch.
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunter_button_pusher_v0.8.lsl b/huffware/huffotronic_jaunter_updater_v5.1/jaunter_button_pusher_v0.8.lsl
new file mode 100755 (executable)
index 0000000..9b5e315
--- /dev/null
@@ -0,0 +1,123 @@
+
+// huffware script: jaunter button pusher, by fred huffhines
+//
+// the button pusher script warped into service for jaunters.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+string JAUNT_NEXT_BUTTON_NAME = "next";
+string JAUNT_MENU_BUTTON_NAME = "menu";
+
+// the button pushing API.
+//////////////
+integer BUTTON_PUSHER_HUFFWARE_ID = 10029;
+    // a unique ID within the huffware system for this script.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+string BUTTON_PUSHED_ALERT = "#btnp";
+    // this event is generated when the button is pushed.  the number parameter will be
+    // the huffware id plus the reply distance.  the id parameter in the link message will
+    // contain the name of the button that was pushed.
+//////////////
+
+float MENU_TIMER_FOR_TOUCH = 0.8;  // click hold delay before we decide they want the menu.
+
+key last_toucher;  // the last person who touched the jaunter.
+
+integer sent_menu_event = FALSE;  // true when we just sent out a menu event.
+
+//////////////
+
+handle_timer()
+{
+    if (last_toucher != NULL_KEY) {
+//log_it("decided to send menu event!");
+        // this is a timer elapsing for a touch-hold menu event.
+        send_menu_button_event();
+        last_toucher = NULL_KEY;
+        llSetTimerEvent(0.0);
+        sent_menu_event = TRUE;
+        return;
+    }
+}
+
+// generates our next button alert, once the user has finished clicking on the button.
+send_next_button_event()
+{
+    llMessageLinked(LINK_SET, BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE,
+        BUTTON_PUSHED_ALERT, JAUNT_NEXT_BUTTON_NAME);
+}
+
+// tells the jaunter to show the menu of places.
+send_menu_button_event()
+{
+    llMessageLinked(LINK_SET, BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE,
+        BUTTON_PUSHED_ALERT, wrap_parameters([JAUNT_MENU_BUTTON_NAME, last_toucher]));
+}
+
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+
+///////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+    }
+
+    touch_start(integer total_number) {
+        if (llDetectedLinkNumber(0) != llGetLinkNumber()) return;
+//log_it("touch start");
+        llSetTimerEvent(MENU_TIMER_FOR_TOUCH);
+            // how long before "hold touch" kicks in and we show the destination menu.
+        last_toucher = llDetectedKey(0);
+    }
+
+    timer() { handle_timer(); }
+
+    touch_end(integer total_number)
+    {
+        if (llDetectedLinkNumber(0) != llGetLinkNumber()) return;
+//log_it("touch end");
+        if (sent_menu_event) {
+            // don't send a click event if we popped the menu.            
+            sent_menu_event = FALSE;
+            return;
+        }
+        // clear timer since we got to here.
+        llSetTimerEvent(0.0);
+        last_toucher = NULL_KEY;
+        send_next_button_event();
+    }
+}
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunter_button_pusher_v0.8.txt b/huffware/huffotronic_jaunter_updater_v5.1/jaunter_button_pusher_v0.8.txt
deleted file mode 100755 (executable)
index 9b5e315..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-
-// huffware script: jaunter button pusher, by fred huffhines
-//
-// the button pusher script warped into service for jaunters.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-string JAUNT_NEXT_BUTTON_NAME = "next";
-string JAUNT_MENU_BUTTON_NAME = "menu";
-
-// the button pushing API.
-//////////////
-integer BUTTON_PUSHER_HUFFWARE_ID = 10029;
-    // a unique ID within the huffware system for this script.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-string BUTTON_PUSHED_ALERT = "#btnp";
-    // this event is generated when the button is pushed.  the number parameter will be
-    // the huffware id plus the reply distance.  the id parameter in the link message will
-    // contain the name of the button that was pushed.
-//////////////
-
-float MENU_TIMER_FOR_TOUCH = 0.8;  // click hold delay before we decide they want the menu.
-
-key last_toucher;  // the last person who touched the jaunter.
-
-integer sent_menu_event = FALSE;  // true when we just sent out a menu event.
-
-//////////////
-
-handle_timer()
-{
-    if (last_toucher != NULL_KEY) {
-//log_it("decided to send menu event!");
-        // this is a timer elapsing for a touch-hold menu event.
-        send_menu_button_event();
-        last_toucher = NULL_KEY;
-        llSetTimerEvent(0.0);
-        sent_menu_event = TRUE;
-        return;
-    }
-}
-
-// generates our next button alert, once the user has finished clicking on the button.
-send_next_button_event()
-{
-    llMessageLinked(LINK_SET, BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE,
-        BUTTON_PUSHED_ALERT, JAUNT_NEXT_BUTTON_NAME);
-}
-
-// tells the jaunter to show the menu of places.
-send_menu_button_event()
-{
-    llMessageLinked(LINK_SET, BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE,
-        BUTTON_PUSHED_ALERT, wrap_parameters([JAUNT_MENU_BUTTON_NAME, last_toucher]));
-}
-
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-
-///////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-    }
-
-    touch_start(integer total_number) {
-        if (llDetectedLinkNumber(0) != llGetLinkNumber()) return;
-//log_it("touch start");
-        llSetTimerEvent(MENU_TIMER_FOR_TOUCH);
-            // how long before "hold touch" kicks in and we show the destination menu.
-        last_toucher = llDetectedKey(0);
-    }
-
-    timer() { handle_timer(); }
-
-    touch_end(integer total_number)
-    {
-        if (llDetectedLinkNumber(0) != llGetLinkNumber()) return;
-//log_it("touch end");
-        if (sent_menu_event) {
-            // don't send a click event if we popped the menu.            
-            sent_menu_event = FALSE;
-            return;
-        }
-        // clear timer since we got to here.
-        llSetTimerEvent(0.0);
-        last_toucher = NULL_KEY;
-        send_next_button_event();
-    }
-}
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunting_library_v15.9.lsl b/huffware/huffotronic_jaunter_updater_v5.1/jaunting_library_v15.9.lsl
new file mode 100755 (executable)
index 0000000..4d65cee
--- /dev/null
@@ -0,0 +1,551 @@
+
+// huffware script: jaunting library, by fred huffhines, released under GPL-v3 license.
+//
+// this script is a library of useful teleportation and movement calls.  it should be added
+// into an object along with other scripts that use the library.  the jaunting library
+// responds to linked messages as commands.
+// parts of this script are based on warpPos from "Teleporter Script v 3.0 by Asira Sakai",
+// which was found at the LSL wiki.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+float PROXIMITY_REQUIRED = 0.1;
+    // how close we must be to the target location to call the jaunt done.
+    // we make this fairly low accuracy since we don't want jumps in space to immediately
+    // be counted as failures.
+
+// the most jumps the script will try to take.  the overall distance from the start
+// to the end can be 10 * MAXIMUM_JUMPS_PER_CALL meters.
+integer MAXIMUM_JUMPS_PER_CALL = 84;
+
+// global variables...
+
+vector last_posn;  // used to calculate jump distances.
+
+// jaunting library link message API...
+//////////////
+// do not redefine these constants.
+integer JAUNT_HUFFWARE_ID = 10008;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+// commands available via the jaunting library:
+string JAUNT_COMMAND = "#jaunt#";
+    // command used to tell jaunt script to move object.  pass a vector with the location.
+string FULL_STOP_COMMAND = "#fullstop#";
+    // command used to bring object to a halt.
+string REVERSE_VELOCITY_COMMAND = "#reverse#";
+    // makes the object reverse its velocity and travel back from whence it came.
+string SET_VELOCITY_COMMAND = "#setvelocity#";
+    // makes the velocity equal to the vector passed as the first parameter.
+string JAUNT_UP_COMMAND = "#jauntup#";
+string JAUNT_DOWN_COMMAND = "#jauntdown#";
+    // commands for height adjustment.  pass a float for number of meters to move.
+string JAUNT_LIST_COMMAND = "#jauntlist#";
+    // like regular jaunt, but expects a list of vectors as the first parameter; this list
+    // should be in the jaunter notecard format (separated by pipe characters).
+    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
+//////////////
+
+// returns what we consider to be safe to do in one big jump.
+float distance_safe_to_jaunt() { return (float)(MAXIMUM_JUMPS_PER_CALL - 4) * 10.0; }
+
+// tests whether the destination is safe for an object to enter.
+integer safe_for_entry(vector where)
+{
+    if (outside_of_sim(where)) {
+        // that's an obvious wrong idea; it tends to break us.
+        return FALSE;
+    }
+    return TRUE;
+}
+
+// helper function for warp_across_list.  this adds one jump vector to the
+// list of rules as long as the destination is interesting.
+list process_warp_item(vector next_jump)
+{
+//log_it("mem: " + (string)llGetFreeMemory());
+    // calculate the number of jumps needed.
+    integer jumps = (integer)(llVecDist(next_jump, last_posn) / 10.0) + 1;
+    last_posn = next_jump;  // record for next check.
+    // set up our list which we'll replicate.
+    list rules = [ PRIM_POSITION, next_jump ];
+    // Try and avoid stack/heap collisions.
+    if (jumps > MAXIMUM_JUMPS_PER_CALL - 1) jumps = MAXIMUM_JUMPS_PER_CALL;
+    // add the rules repeatedly to get the effective overall jump done.
+    integer count = 1;
+    while ( (count = count << 1) < jumps)
+        rules += rules;
+    // magnify the rule list before really adding it.  this gets us to the proper
+    // final number of jumps.
+    return rules + llList2List(rules, (count - jumps) << 1 - 2, count);
+}
+
+// originally based on warpPos from lsl wiki but drastically modified.
+// uses a set of transfer points instead of a single target.
+list warp_across_list(list full_journey, integer forwards)
+{
+    // make sure the list didn't run out.
+    if (llGetListLength(full_journey) == 0) return [];
+    if (forwards) {
+        // forwards traversal of the list.
+        vector next_jump = (vector)llList2String(full_journey, 0);
+        // shortcut the jumps if we're already there.
+        if (next_jump == llGetPos())
+            return warp_across_list(chop_list(full_journey, 1,
+                llGetListLength(full_journey) - 1), forwards);
+        // calculate our trajectory for the next jump and add in all subsequent jumps.
+        return process_warp_item(next_jump)
+            + warp_across_list(chop_list(full_journey, 1, llGetListLength(full_journey) - 1), forwards);
+    } else {
+        // reverse traversal of the list.
+        vector next_jump = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
+        // shortcut the jumps if we're already there.
+        if (next_jump == llGetPos())
+            return warp_across_list(chop_list(full_journey, 0,
+                llGetListLength(full_journey) - 2), forwards);
+        // calculate our trajectory for the next jump and add in all subsequent jumps.
+        return process_warp_item(next_jump)
+            + warp_across_list(chop_list(full_journey, 0, llGetListLength(full_journey) - 2), forwards);
+    }
+}
+
+// the main function that performs the jaunting process.
+// now also supports adding a rotation into the mix to avoid paying the extra delay
+// cost of calling llSetRot.
+jaunt(list full_journey, integer forwards, string command_used,
+    integer use_rotation, rotation rot, integer reply_to_request)
+{
+//log_it("jaunt: fullj=" + (string)full_journey + " forew=" + (string)forwards);
+    // set up our global variables...
+    last_posn = llGetPos();
+    // calculate the trip and run it.
+    list rot_add;
+    if (use_rotation)
+        rot_add = [ PRIM_ROTATION, rot ];
+    llSetPrimitiveParams(warp_across_list(full_journey, forwards) + rot_add);
+    if (reply_to_request) {
+        // pick out the last target in the list based on the direction we're moving.
+        integer last_indy = 0;
+        if (forwards == TRUE) last_indy = llGetListLength(full_journey) - 1;
+        vector last_jump = (vector)llList2String(full_journey, last_indy);
+        // final judge of success here is how close we got to the target.
+        integer landed_there = (llVecDist(llGetPos(), last_jump) <= PROXIMITY_REQUIRED);
+        send_reply(LINK_THIS, [landed_there, llGetPos()], command_used);
+    }
+}
+
+//////////////
+
+// sets the object's speed to "new_velocity".
+// if "local_axis" is TRUE, then it will be relative to the object's
+// own local coordinates.
+set_velocity(vector new_velocity, integer local_axis)
+{
+    vector current_velocity = llGetVel();
+         
+    if (local_axis) {
+        rotation rot = llGetRot();
+        current_velocity /= rot;  // undo the rotation.
+    }
+    
+    new_velocity -= current_velocity;
+    new_velocity *= llGetMass();
+    
+    llApplyImpulse(new_velocity, local_axis);
+}
+
+// attempts to bring the object to a complete stop.
+full_stop()
+{
+    llSetForce(<0,0,0>, FALSE);
+    set_velocity(<0,0,0>, FALSE);
+}
+
+// sends an object back along its trajectory.
+reverse_velocity(integer local_axis)
+{
+    vector current_velocity = llGetVel();
+    if (local_axis) {
+        rotation rot = llGetRot();
+        current_velocity /= rot;  // undo the rotation.
+    }
+    vector new_velocity = -2 * current_velocity;
+    new_velocity *= llGetMass();
+    llApplyImpulse(new_velocity, local_axis);
+}
+
+// teleports to the new "location", if possible.  does not change object's phantom / physical
+// states.  this will do the jaunt in multiple steps if the distance from here to "location"
+// is too large.
+apportioned_jaunt(vector location, string command_used, integer use_rotation, rotation rot,
+    integer should_send_reply)
+{
+    if (!safe_for_entry(location)) {
+        // that's not good.  we should not allow the script to get broken.
+        if (should_send_reply)
+            send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
+        return;
+    }
+    // go to position specified, by leapfrogs if too long.
+    integer chunk_of_jump;
+    integer MAX_CHUNKS = 200;  // multiplies the distance a single jaunt can cover.
+    for (chunk_of_jump = 0; chunk_of_jump < MAX_CHUNKS; chunk_of_jump++) {
+        vector interim_vec = location - llGetPos();
+        float jump_dist = llVecDist(llGetPos(), location);
+        integer reply_needed = TRUE;
+        if (jump_dist > distance_safe_to_jaunt()) {
+            // the entire distance cannot be jumped.  do the part of it that fits.
+            float proportion_can_do = distance_safe_to_jaunt() / jump_dist;
+            interim_vec *= proportion_can_do;
+            reply_needed = FALSE;  // don't reply when this is not full jump.
+        }
+        interim_vec += llGetPos();  // bias jump back to where we are.
+//log_it("jumping from " + (string)llGetPos() + " to " + (string)interim_vec);
+        jaunt([llGetPos(), interim_vec], TRUE, command_used, use_rotation, rot,
+            reply_needed && should_send_reply);
+        float dist_now = llVecDist(llGetPos(), interim_vec);
+        if (dist_now > PROXIMITY_REQUIRED) {
+//log_it("failed to make interim jump, dist left is " + (string)dist_now);
+            // bail out.  we failed to get as far as we thought we should.
+            chunk_of_jump = MAX_CHUNKS + 10;
+            if (!reply_needed) {
+                // we need to send the reply we hadn't sent yet.
+                if (should_send_reply)
+                    send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
+            }
+        } else if (llVecDist(llGetPos(), location) <= PROXIMITY_REQUIRED) {
+            // leave loop for a different reason; we got there.
+            chunk_of_jump = MAX_CHUNKS + 10;
+            if (!reply_needed) {
+                // we need to send the reply we hadn't sent yet.
+                if (should_send_reply)
+                    send_reply(LINK_THIS, [TRUE, llGetPos()], command_used);
+            }
+        }
+    }
+}
+
+// the entire distance embodied in the list of targets.  this is a little smart,
+// in that if there's only one target, we assume we're going from "here" to that
+// one target.
+float total_jaunt_distance(list targets)
+{
+    if (!llGetListLength(targets)) return 0.0;
+    // add in "this" location if they omitted it.
+    if (llGetListLength(targets) < 2)
+        targets = [ llGetPos() ] + targets;
+    integer disindy;
+    float total_dist = 0.0;
+    vector prev = (vector)llList2String(targets, 0);
+    for (disindy = 1; disindy < llGetListLength(targets); disindy++) {
+        vector next = (vector)llList2String(targets, disindy);
+        total_dist += llVecDist(prev, next);
+        prev = next;
+    }
+    return total_dist;
+}
+
+// jaunts to a target via a set of intermediate locations.  can either go forwards
+// through the list or backwards.
+phantom_jaunt_to_list(list targets, integer forwards, string command_used,
+    integer use_rotation, rotation rot)
+{
+    vector final_loc;
+    if (forwards) final_loc = (vector)llList2String(targets, llGetListLength(targets) - 1);
+    else final_loc = (vector)llList2String(targets, 0);
+
+//hmmm: check each destination in list??
+    if (!safe_for_entry(final_loc)) {
+        // that's not good.  we should not allow the script to get broken.
+        send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
+        return;
+    }
+    
+    // this turns off the physics property for the object, so that jaunt and
+    // llSetPos will still work.  this became necessary due to havok4.
+    integer original_phantomosity = llGetStatus(STATUS_PHANTOM);
+    integer original_physicality = llGetStatus(STATUS_PHYSICS);
+    if (original_physicality != FALSE) llSetStatus(STATUS_PHYSICS, FALSE);
+    if (original_phantomosity != TRUE) llSetStatus(STATUS_PHANTOM, TRUE);
+
+    integer send_reply_still = TRUE;  // true if we should send a reply when done.
+
+    // iterate through our list of targets and either we will jaunt to the next
+    // place directly or we will have to wrap a few destinations due to sim crossing.
+    while (llGetListLength(targets) > 0) {
+        vector next_loc;
+        if (forwards) next_loc = (vector)llList2String(targets, 0);
+        else next_loc = (vector)llList2String(targets, llGetListLength(targets) - 1);
+        if (outside_of_sim(next_loc)) {
+            log_it("bad jaunt path: first target is out of sim.");
+            send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
+            return;  // skip that badness.
+        }
+        
+        // check how much total distance we have in the path that's left.  if it's under our
+        // limit, then we'll just take it in one jump.
+        float total_dist = total_jaunt_distance(targets);
+
+        // if we're below the threshold, we'll just jump now.
+        integer already_jumped = FALSE;
+        if (total_dist < distance_safe_to_jaunt()) {
+            jaunt(targets, forwards, command_used, use_rotation, rot, TRUE);
+            targets = [];  // reset the list now.
+            send_reply_still = FALSE;  // we have already sent the reply in jaunt().
+            already_jumped = TRUE;  // don't do anything else.
+        }
+        if (!already_jumped) {
+            vector next_plus_1 = ZERO_VECTOR;  // default cannot fail our "is inside sim" check.
+            if (llGetListLength(targets) > 1) {
+                if (forwards) next_plus_1 = (vector)llList2String(targets, 1);
+                else next_plus_1 = (vector)llList2String(targets, llGetListLength(targets) - 2);
+            }
+            if (outside_of_sim(next_plus_1)) {
+//hmmm: eventually find all the negative ones in a row and do them in combo, rather than
+//      just giving up here and doing a jaunt to the rest..
+                jaunt(targets, forwards, command_used, use_rotation, rot, TRUE);
+                targets = [];  // reset the list now.
+                send_reply_still = FALSE;  // we have already sent the reply in jaunt().
+            } else {
+                // we've passed the negativity test, so we can at least jump to the next place.
+                
+                // zap the next location, since we're about to jump there.
+                integer zap_pos = 0;
+                if (!forwards) zap_pos = llGetListLength(targets) - 1;
+                targets = llDeleteSubList(targets, zap_pos, zap_pos);        
+        
+                // only bother jumping if we're not already there.
+                if (llVecDist(next_loc, llGetPos()) > PROXIMITY_REQUIRED) {
+                    apportioned_jaunt(next_loc, command_used, use_rotation, rot, FALSE);
+                }
+            }
+        }
+    }
+
+    if (send_reply_still) {
+        integer yippee = TRUE;  // assume we succeeded until we prove otherwise.
+        if (llVecDist(final_loc, llGetPos()) > PROXIMITY_REQUIRED)
+            yippee = FALSE;
+        send_reply(LINK_THIS, [yippee, llGetPos()], command_used);
+    }
+
+    // return to prior characteristics.
+    if (original_phantomosity != TRUE) llSetStatus(STATUS_PHANTOM, original_phantomosity);
+    if (original_physicality != FALSE) llSetStatus(STATUS_PHYSICS, original_physicality);
+}
+
+// implements our API for jumping around.
+handle_link_message(integer sender, integer huff_id, string msg, key id)
+{
+    // separate the list out
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    if (msg == JAUNT_COMMAND) {
+        // use list to string to avoid non-conversions.
+        vector v = (vector)llList2String(parms, 0);
+        rotation rot = <0.0, 0.0, 0.0, 1.0>;
+        integer gave_rot = llGetListLength(parms) > 1;
+        if (gave_rot) rot = (rotation)llList2String(parms, 1);  // ooh, they gave us a rotational value also.
+//        log_it("gave rot? " + (string)gave_rot + " rot=" + (string)rot);
+        phantom_jaunt_to_list([llGetPos(), v], TRUE, msg, gave_rot, rot);
+    } else if (msg == FULL_STOP_COMMAND) {
+        full_stop();
+    } else if (msg == REVERSE_VELOCITY_COMMAND) {
+        reverse_velocity(FALSE);
+    } else if (msg == SET_VELOCITY_COMMAND) {            
+        vector v = (vector)llList2String(parms, 0);
+//log_it("jaunting lib received set velocity request for " + (string)v);
+        set_velocity(v, FALSE);
+    } else if (msg == JAUNT_UP_COMMAND) {
+        phantom_jaunt_to_list([ llGetPos(), llGetPos() + <0.0, 0.0, llList2Float(parms, 0)> ],
+            TRUE, msg, FALSE, ZERO_ROTATION);
+    } else if (msg == JAUNT_DOWN_COMMAND) {
+        phantom_jaunt_to_list([ llGetPos(), llGetPos() + <0.0, 0.0, -llList2Float(parms, 0)> ],
+            TRUE, msg, FALSE, ZERO_ROTATION);
+    } else if (msg == JAUNT_LIST_COMMAND) {
+        string destination_list = llList2String(parms, 0);
+        list targets = llParseString2List(destination_list, [HUFFWARE_ITEM_SEPARATOR], []);
+        destination_list = "";
+        integer forwards = TRUE;
+        // snag the directionality for the list, if specified.
+        if (llGetListLength(parms) > 1) forwards = llList2Integer(parms, 1);
+        rotation rot = <0.0, 0.0, 0.0, 1.0>;
+        integer gave_rot = llGetListLength(parms) > 2;
+        if (gave_rot) rot = llList2Rot(parms, 2);  // ooh, they gave us a rotational value also.        
+        phantom_jaunt_to_list(targets, forwards, msg, gave_rot, rot);
+        targets = [];
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
+}
+//////////////
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply(integer destination, list parms, string command)
+{
+    llMessageLinked(destination, JAUNT_HUFFWARE_ID + REPLY_DISTANCE, command,
+        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
+integer valid_sim_value(float to_check)
+{
+    if (to_check < 0.0) return FALSE;
+    if (to_check >= 257.0) return FALSE;
+    return TRUE;
+}
+
+integer outside_of_sim(vector to_check)
+{
+    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
+}
+
+///////////////
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); }
+    
+    link_message(integer sender, integer huff_id, string msg, key id) {
+        if (huff_id != JAUNT_HUFFWARE_ID) return;  // not our responsibility.
+        handle_link_message(sender, huff_id, msg, id);
+    }
+}
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/jaunting_library_v15.9.txt b/huffware/huffotronic_jaunter_updater_v5.1/jaunting_library_v15.9.txt
deleted file mode 100755 (executable)
index 4d65cee..0000000
+++ /dev/null
@@ -1,551 +0,0 @@
-
-// huffware script: jaunting library, by fred huffhines, released under GPL-v3 license.
-//
-// this script is a library of useful teleportation and movement calls.  it should be added
-// into an object along with other scripts that use the library.  the jaunting library
-// responds to linked messages as commands.
-// parts of this script are based on warpPos from "Teleporter Script v 3.0 by Asira Sakai",
-// which was found at the LSL wiki.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-float PROXIMITY_REQUIRED = 0.1;
-    // how close we must be to the target location to call the jaunt done.
-    // we make this fairly low accuracy since we don't want jumps in space to immediately
-    // be counted as failures.
-
-// the most jumps the script will try to take.  the overall distance from the start
-// to the end can be 10 * MAXIMUM_JUMPS_PER_CALL meters.
-integer MAXIMUM_JUMPS_PER_CALL = 84;
-
-// global variables...
-
-vector last_posn;  // used to calculate jump distances.
-
-// jaunting library link message API...
-//////////////
-// do not redefine these constants.
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-// commands available via the jaunting library:
-string JAUNT_COMMAND = "#jaunt#";
-    // command used to tell jaunt script to move object.  pass a vector with the location.
-string FULL_STOP_COMMAND = "#fullstop#";
-    // command used to bring object to a halt.
-string REVERSE_VELOCITY_COMMAND = "#reverse#";
-    // makes the object reverse its velocity and travel back from whence it came.
-string SET_VELOCITY_COMMAND = "#setvelocity#";
-    // makes the velocity equal to the vector passed as the first parameter.
-string JAUNT_UP_COMMAND = "#jauntup#";
-string JAUNT_DOWN_COMMAND = "#jauntdown#";
-    // commands for height adjustment.  pass a float for number of meters to move.
-string JAUNT_LIST_COMMAND = "#jauntlist#";
-    // like regular jaunt, but expects a list of vectors as the first parameter; this list
-    // should be in the jaunter notecard format (separated by pipe characters).
-    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
-//////////////
-
-// returns what we consider to be safe to do in one big jump.
-float distance_safe_to_jaunt() { return (float)(MAXIMUM_JUMPS_PER_CALL - 4) * 10.0; }
-
-// tests whether the destination is safe for an object to enter.
-integer safe_for_entry(vector where)
-{
-    if (outside_of_sim(where)) {
-        // that's an obvious wrong idea; it tends to break us.
-        return FALSE;
-    }
-    return TRUE;
-}
-
-// helper function for warp_across_list.  this adds one jump vector to the
-// list of rules as long as the destination is interesting.
-list process_warp_item(vector next_jump)
-{
-//log_it("mem: " + (string)llGetFreeMemory());
-    // calculate the number of jumps needed.
-    integer jumps = (integer)(llVecDist(next_jump, last_posn) / 10.0) + 1;
-    last_posn = next_jump;  // record for next check.
-    // set up our list which we'll replicate.
-    list rules = [ PRIM_POSITION, next_jump ];
-    // Try and avoid stack/heap collisions.
-    if (jumps > MAXIMUM_JUMPS_PER_CALL - 1) jumps = MAXIMUM_JUMPS_PER_CALL;
-    // add the rules repeatedly to get the effective overall jump done.
-    integer count = 1;
-    while ( (count = count << 1) < jumps)
-        rules += rules;
-    // magnify the rule list before really adding it.  this gets us to the proper
-    // final number of jumps.
-    return rules + llList2List(rules, (count - jumps) << 1 - 2, count);
-}
-
-// originally based on warpPos from lsl wiki but drastically modified.
-// uses a set of transfer points instead of a single target.
-list warp_across_list(list full_journey, integer forwards)
-{
-    // make sure the list didn't run out.
-    if (llGetListLength(full_journey) == 0) return [];
-    if (forwards) {
-        // forwards traversal of the list.
-        vector next_jump = (vector)llList2String(full_journey, 0);
-        // shortcut the jumps if we're already there.
-        if (next_jump == llGetPos())
-            return warp_across_list(chop_list(full_journey, 1,
-                llGetListLength(full_journey) - 1), forwards);
-        // calculate our trajectory for the next jump and add in all subsequent jumps.
-        return process_warp_item(next_jump)
-            + warp_across_list(chop_list(full_journey, 1, llGetListLength(full_journey) - 1), forwards);
-    } else {
-        // reverse traversal of the list.
-        vector next_jump = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
-        // shortcut the jumps if we're already there.
-        if (next_jump == llGetPos())
-            return warp_across_list(chop_list(full_journey, 0,
-                llGetListLength(full_journey) - 2), forwards);
-        // calculate our trajectory for the next jump and add in all subsequent jumps.
-        return process_warp_item(next_jump)
-            + warp_across_list(chop_list(full_journey, 0, llGetListLength(full_journey) - 2), forwards);
-    }
-}
-
-// the main function that performs the jaunting process.
-// now also supports adding a rotation into the mix to avoid paying the extra delay
-// cost of calling llSetRot.
-jaunt(list full_journey, integer forwards, string command_used,
-    integer use_rotation, rotation rot, integer reply_to_request)
-{
-//log_it("jaunt: fullj=" + (string)full_journey + " forew=" + (string)forwards);
-    // set up our global variables...
-    last_posn = llGetPos();
-    // calculate the trip and run it.
-    list rot_add;
-    if (use_rotation)
-        rot_add = [ PRIM_ROTATION, rot ];
-    llSetPrimitiveParams(warp_across_list(full_journey, forwards) + rot_add);
-    if (reply_to_request) {
-        // pick out the last target in the list based on the direction we're moving.
-        integer last_indy = 0;
-        if (forwards == TRUE) last_indy = llGetListLength(full_journey) - 1;
-        vector last_jump = (vector)llList2String(full_journey, last_indy);
-        // final judge of success here is how close we got to the target.
-        integer landed_there = (llVecDist(llGetPos(), last_jump) <= PROXIMITY_REQUIRED);
-        send_reply(LINK_THIS, [landed_there, llGetPos()], command_used);
-    }
-}
-
-//////////////
-
-// sets the object's speed to "new_velocity".
-// if "local_axis" is TRUE, then it will be relative to the object's
-// own local coordinates.
-set_velocity(vector new_velocity, integer local_axis)
-{
-    vector current_velocity = llGetVel();
-         
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    
-    new_velocity -= current_velocity;
-    new_velocity *= llGetMass();
-    
-    llApplyImpulse(new_velocity, local_axis);
-}
-
-// attempts to bring the object to a complete stop.
-full_stop()
-{
-    llSetForce(<0,0,0>, FALSE);
-    set_velocity(<0,0,0>, FALSE);
-}
-
-// sends an object back along its trajectory.
-reverse_velocity(integer local_axis)
-{
-    vector current_velocity = llGetVel();
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    vector new_velocity = -2 * current_velocity;
-    new_velocity *= llGetMass();
-    llApplyImpulse(new_velocity, local_axis);
-}
-
-// teleports to the new "location", if possible.  does not change object's phantom / physical
-// states.  this will do the jaunt in multiple steps if the distance from here to "location"
-// is too large.
-apportioned_jaunt(vector location, string command_used, integer use_rotation, rotation rot,
-    integer should_send_reply)
-{
-    if (!safe_for_entry(location)) {
-        // that's not good.  we should not allow the script to get broken.
-        if (should_send_reply)
-            send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-        return;
-    }
-    // go to position specified, by leapfrogs if too long.
-    integer chunk_of_jump;
-    integer MAX_CHUNKS = 200;  // multiplies the distance a single jaunt can cover.
-    for (chunk_of_jump = 0; chunk_of_jump < MAX_CHUNKS; chunk_of_jump++) {
-        vector interim_vec = location - llGetPos();
-        float jump_dist = llVecDist(llGetPos(), location);
-        integer reply_needed = TRUE;
-        if (jump_dist > distance_safe_to_jaunt()) {
-            // the entire distance cannot be jumped.  do the part of it that fits.
-            float proportion_can_do = distance_safe_to_jaunt() / jump_dist;
-            interim_vec *= proportion_can_do;
-            reply_needed = FALSE;  // don't reply when this is not full jump.
-        }
-        interim_vec += llGetPos();  // bias jump back to where we are.
-//log_it("jumping from " + (string)llGetPos() + " to " + (string)interim_vec);
-        jaunt([llGetPos(), interim_vec], TRUE, command_used, use_rotation, rot,
-            reply_needed && should_send_reply);
-        float dist_now = llVecDist(llGetPos(), interim_vec);
-        if (dist_now > PROXIMITY_REQUIRED) {
-//log_it("failed to make interim jump, dist left is " + (string)dist_now);
-            // bail out.  we failed to get as far as we thought we should.
-            chunk_of_jump = MAX_CHUNKS + 10;
-            if (!reply_needed) {
-                // we need to send the reply we hadn't sent yet.
-                if (should_send_reply)
-                    send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-            }
-        } else if (llVecDist(llGetPos(), location) <= PROXIMITY_REQUIRED) {
-            // leave loop for a different reason; we got there.
-            chunk_of_jump = MAX_CHUNKS + 10;
-            if (!reply_needed) {
-                // we need to send the reply we hadn't sent yet.
-                if (should_send_reply)
-                    send_reply(LINK_THIS, [TRUE, llGetPos()], command_used);
-            }
-        }
-    }
-}
-
-// the entire distance embodied in the list of targets.  this is a little smart,
-// in that if there's only one target, we assume we're going from "here" to that
-// one target.
-float total_jaunt_distance(list targets)
-{
-    if (!llGetListLength(targets)) return 0.0;
-    // add in "this" location if they omitted it.
-    if (llGetListLength(targets) < 2)
-        targets = [ llGetPos() ] + targets;
-    integer disindy;
-    float total_dist = 0.0;
-    vector prev = (vector)llList2String(targets, 0);
-    for (disindy = 1; disindy < llGetListLength(targets); disindy++) {
-        vector next = (vector)llList2String(targets, disindy);
-        total_dist += llVecDist(prev, next);
-        prev = next;
-    }
-    return total_dist;
-}
-
-// jaunts to a target via a set of intermediate locations.  can either go forwards
-// through the list or backwards.
-phantom_jaunt_to_list(list targets, integer forwards, string command_used,
-    integer use_rotation, rotation rot)
-{
-    vector final_loc;
-    if (forwards) final_loc = (vector)llList2String(targets, llGetListLength(targets) - 1);
-    else final_loc = (vector)llList2String(targets, 0);
-
-//hmmm: check each destination in list??
-    if (!safe_for_entry(final_loc)) {
-        // that's not good.  we should not allow the script to get broken.
-        send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-        return;
-    }
-    
-    // this turns off the physics property for the object, so that jaunt and
-    // llSetPos will still work.  this became necessary due to havok4.
-    integer original_phantomosity = llGetStatus(STATUS_PHANTOM);
-    integer original_physicality = llGetStatus(STATUS_PHYSICS);
-    if (original_physicality != FALSE) llSetStatus(STATUS_PHYSICS, FALSE);
-    if (original_phantomosity != TRUE) llSetStatus(STATUS_PHANTOM, TRUE);
-
-    integer send_reply_still = TRUE;  // true if we should send a reply when done.
-
-    // iterate through our list of targets and either we will jaunt to the next
-    // place directly or we will have to wrap a few destinations due to sim crossing.
-    while (llGetListLength(targets) > 0) {
-        vector next_loc;
-        if (forwards) next_loc = (vector)llList2String(targets, 0);
-        else next_loc = (vector)llList2String(targets, llGetListLength(targets) - 1);
-        if (outside_of_sim(next_loc)) {
-            log_it("bad jaunt path: first target is out of sim.");
-            send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-            return;  // skip that badness.
-        }
-        
-        // check how much total distance we have in the path that's left.  if it's under our
-        // limit, then we'll just take it in one jump.
-        float total_dist = total_jaunt_distance(targets);
-
-        // if we're below the threshold, we'll just jump now.
-        integer already_jumped = FALSE;
-        if (total_dist < distance_safe_to_jaunt()) {
-            jaunt(targets, forwards, command_used, use_rotation, rot, TRUE);
-            targets = [];  // reset the list now.
-            send_reply_still = FALSE;  // we have already sent the reply in jaunt().
-            already_jumped = TRUE;  // don't do anything else.
-        }
-        if (!already_jumped) {
-            vector next_plus_1 = ZERO_VECTOR;  // default cannot fail our "is inside sim" check.
-            if (llGetListLength(targets) > 1) {
-                if (forwards) next_plus_1 = (vector)llList2String(targets, 1);
-                else next_plus_1 = (vector)llList2String(targets, llGetListLength(targets) - 2);
-            }
-            if (outside_of_sim(next_plus_1)) {
-//hmmm: eventually find all the negative ones in a row and do them in combo, rather than
-//      just giving up here and doing a jaunt to the rest..
-                jaunt(targets, forwards, command_used, use_rotation, rot, TRUE);
-                targets = [];  // reset the list now.
-                send_reply_still = FALSE;  // we have already sent the reply in jaunt().
-            } else {
-                // we've passed the negativity test, so we can at least jump to the next place.
-                
-                // zap the next location, since we're about to jump there.
-                integer zap_pos = 0;
-                if (!forwards) zap_pos = llGetListLength(targets) - 1;
-                targets = llDeleteSubList(targets, zap_pos, zap_pos);        
-        
-                // only bother jumping if we're not already there.
-                if (llVecDist(next_loc, llGetPos()) > PROXIMITY_REQUIRED) {
-                    apportioned_jaunt(next_loc, command_used, use_rotation, rot, FALSE);
-                }
-            }
-        }
-    }
-
-    if (send_reply_still) {
-        integer yippee = TRUE;  // assume we succeeded until we prove otherwise.
-        if (llVecDist(final_loc, llGetPos()) > PROXIMITY_REQUIRED)
-            yippee = FALSE;
-        send_reply(LINK_THIS, [yippee, llGetPos()], command_used);
-    }
-
-    // return to prior characteristics.
-    if (original_phantomosity != TRUE) llSetStatus(STATUS_PHANTOM, original_phantomosity);
-    if (original_physicality != FALSE) llSetStatus(STATUS_PHYSICS, original_physicality);
-}
-
-// implements our API for jumping around.
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-    // separate the list out
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    if (msg == JAUNT_COMMAND) {
-        // use list to string to avoid non-conversions.
-        vector v = (vector)llList2String(parms, 0);
-        rotation rot = <0.0, 0.0, 0.0, 1.0>;
-        integer gave_rot = llGetListLength(parms) > 1;
-        if (gave_rot) rot = (rotation)llList2String(parms, 1);  // ooh, they gave us a rotational value also.
-//        log_it("gave rot? " + (string)gave_rot + " rot=" + (string)rot);
-        phantom_jaunt_to_list([llGetPos(), v], TRUE, msg, gave_rot, rot);
-    } else if (msg == FULL_STOP_COMMAND) {
-        full_stop();
-    } else if (msg == REVERSE_VELOCITY_COMMAND) {
-        reverse_velocity(FALSE);
-    } else if (msg == SET_VELOCITY_COMMAND) {            
-        vector v = (vector)llList2String(parms, 0);
-//log_it("jaunting lib received set velocity request for " + (string)v);
-        set_velocity(v, FALSE);
-    } else if (msg == JAUNT_UP_COMMAND) {
-        phantom_jaunt_to_list([ llGetPos(), llGetPos() + <0.0, 0.0, llList2Float(parms, 0)> ],
-            TRUE, msg, FALSE, ZERO_ROTATION);
-    } else if (msg == JAUNT_DOWN_COMMAND) {
-        phantom_jaunt_to_list([ llGetPos(), llGetPos() + <0.0, 0.0, -llList2Float(parms, 0)> ],
-            TRUE, msg, FALSE, ZERO_ROTATION);
-    } else if (msg == JAUNT_LIST_COMMAND) {
-        string destination_list = llList2String(parms, 0);
-        list targets = llParseString2List(destination_list, [HUFFWARE_ITEM_SEPARATOR], []);
-        destination_list = "";
-        integer forwards = TRUE;
-        // snag the directionality for the list, if specified.
-        if (llGetListLength(parms) > 1) forwards = llList2Integer(parms, 1);
-        rotation rot = <0.0, 0.0, 0.0, 1.0>;
-        integer gave_rot = llGetListLength(parms) > 2;
-        if (gave_rot) rot = llList2Rot(parms, 2);  // ooh, they gave us a rotational value also.        
-        phantom_jaunt_to_list(targets, forwards, msg, gave_rot, rot);
-        targets = [];
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
-}
-//////////////
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply(integer destination, list parms, string command)
-{
-    llMessageLinked(destination, JAUNT_HUFFWARE_ID + REPLY_DISTANCE, command,
-        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-///////////////
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); }
-    
-    link_message(integer sender, integer huff_id, string msg, key id) {
-        if (huff_id != JAUNT_HUFFWARE_ID) return;  // not our responsibility.
-        handle_link_message(sender, huff_id, msg, id);
-    }
-}
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/menutini_library_v5.9.lsl b/huffware/huffotronic_jaunter_updater_v5.1/menutini_library_v5.9.lsl
new file mode 100755 (executable)
index 0000000..abd2711
--- /dev/null
@@ -0,0 +1,436 @@
+
+// huffware script: menutini library, by fred huffhines.
+//
+// this is a library script for menuing that provides a way to remote control the
+// menu, somewhat.  another script can zing link messages at this script and a menu
+// will be shown based on the specified description and buttons.  when the user
+// selects an answer, that result is sent back in a link message reply.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// useful constants you might want to change:
+
+integer TIMEOUT_FOR_MENU = 42;
+    // timeout for the menu in seconds.
+//hmmm: may want this to be selectable from menu request.
+//      or may even want to never time out!
+//      if we managed a list of ongoing menus, that would work.
+//      currently it cannot.
+
+integer DEBUGGING = FALSE;
+    // if this is true, then extra info will be printed when handling a menu.
+
+string NEXT_MENU_TEXT = "Next >>";
+    // what the next item will say for showing next menu page.
+
+// menutini link message API...
+//////////////
+// do not redefine these constants.
+integer MENUTINI_HUFFWARE_ID = 10009;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string SHOW_MENU_COMMAND = "#menu#";
+    // the command that tells menutini to show a menu defined by parameters
+    // that are passed along.  these must be: the menu name, the menu's title
+    // (which is really the info to show as content in the main box of the menu),
+    // the wrapped list of commands to show as menu buttons, the menu system
+    // channel's for listening, and the key to listen to.
+    // the reply will include: the menu name, the choice made and the key for
+    // the avatar.
+//
+//////////////
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+//
+//////////////
+
+// global variables...
+
+list _private_global_buttons;  // holds onto the active set of menu options.
+string _private_global_av_key;  // the key for the avatar who clicks the menu.
+string _private_global_title;  // holds onto current title text.
+
+integer _menu_base_start = 0;  // position in the items of the current menu.
+
+integer listening_id = 0;
+    // the current id of our listening for the menu.  it's an id returned by LSL
+    // that we need to track so we can cancel the listen.
+
+integer menu_system_channel = 0;
+    // messages come back to us from this channel when user clicks the dialog.
+    // this is set later and the default is meaningless.
+
+string global_menu_name = "";
+    // hangs onto the current menu's name.
+
+//hmmm: note; to manage multiple concurrent menus on different channels,
+//      we must make these into lists.  then the timeouts should apply
+//      individually to these instead of overall (if we even do timeouts;
+//      it's nicer if menus never stop being active).
+
+
+// displays the menu requested.  it's "menu_name" is an internal name that is
+// not displayed to the user.  the "title" is the content shown in the main area
+// of the menu.  "commands_in" is the list of menu items to show as buttons.
+// the "menu_channel" is where the user's clicked response will be sent.  the
+// "listen_to" key is the avatar expected to click the menu, which is needed to
+// listen to his response.
+show_menu(string menu_name, string title, list buttons,
+    integer menu_channel, key listen_to)
+{
+    // save our new parms.
+    global_menu_name = menu_name;
+    _private_global_title = title;
+    _private_global_buttons = buttons;
+    menu_system_channel = menu_channel;
+    _private_global_av_key = listen_to;
+    if (DEBUGGING) {
+        log_it("menu name: " + global_menu_name);
+        log_it("title: " + _private_global_title);
+        log_it("buttons: " + (string)buttons);
+        log_it("channel: " + (string)menu_system_channel);
+        log_it("listen key: " + (string)listen_to);
+    }
+
+    integer add_next = FALSE;  // true if we should add a next menu item.
+
+    // the math here incorporates current button position.
+    integer current = _menu_base_start;
+    integer max_buttons = llGetListLength(buttons) - current;
+
+    if (max_buttons > 12) {
+        // limitation of SL: menus have a max of 12 buttons.
+        max_buttons = 12;
+        add_next = TRUE;
+    } else if (llGetListLength(buttons) > 12) {
+        // we already have been adding next.  let's make sure this gets
+        // a wrap-around next button.
+        add_next = TRUE;
+    }
+    // chop out what we can use in a menu.
+    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
+    if (add_next) {
+        // we were asked to add a menu item for the next screen.
+        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
+    }
+
+    listening_id = llListen(menu_channel, "", listen_to, "");
+    list commands;
+    integer i;
+    // take only the prefix of the string, to avoid getting a length complaint.
+    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
+        string curr = llList2String(trunc_buttons, i);
+        integer last_pos = 23;  // default maximum, highest possible is 24.
+        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
+        curr = llGetSubString(curr, 0, last_pos);
+        commands += curr;
+    }
+    llDialog(listen_to, title, commands, menu_channel);
+    llSetTimerEvent(TIMEOUT_FOR_MENU);
+}
+
+// shuts down any connection we might have had with any active menu.  we will not
+// send any responses after this point (although we might already have responded when
+// the user clicked the menu).
+clear_menu()
+{
+    llListenRemove(listening_id);
+    llSetTimerEvent(0.0);
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+// ours do differ from normal in that we send back the channel as the number parameter
+// instead of enforcing that being MENU_HUFFWARE_ID.
+send_reply(integer destination, integer channel, list parms, string command)
+{
+    llMessageLinked(destination, channel, command,
+        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+// processes the menu requests.
+handle_link_message(integer sender, integer huff_id, string msg, key id)
+{
+    if (huff_id != MENUTINI_HUFFWARE_ID) return;  // not for us.
+
+    if (msg == SHOW_MENU_COMMAND) {
+        _menu_base_start = 0;  // reset the position in the menus.
+        // separate the list out.
+//log_it("id showing: " + id);
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        // toss any existing menu info.
+        clear_menu();
+//log_it("key here early: " + llList2String(parms, 4));
+        show_menu(llList2String(parms, 0), llList2String(parms, 1),
+            llParseString2List(llList2String(parms, 2),
+                [HUFFWARE_ITEM_SEPARATOR], []),
+            (integer)llList2String(parms, 3),
+            (key)llList2String(parms, 4));
+    }
+}
+
+// process the response when the user chooses a menu item.  this causes our
+// caller to be told what was selected.
+process_menu_response(integer channel, string name, key id, string message)
+{
+    if (channel != menu_system_channel) return;  // not for us.
+
+    if (message == NEXT_MENU_TEXT) {
+        // this is the special choice, so we need to go to the next page.
+        _menu_base_start += 11;
+        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
+            // we have wrapped around the list.  go to the start again.
+            _menu_base_start = 0;
+        }
+        show_menu(global_menu_name, _private_global_title,
+            _private_global_buttons, menu_system_channel,
+            _private_global_av_key);
+        return;  // handled by opening a new menu.
+    }
+    
+    string calculated_name;
+    integer indy;
+    // first try for an exact match.
+    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+        string curr = llList2String(_private_global_buttons, indy);
+        if (curr == message) {
+            // correct the answer based on the full button string.
+            calculated_name = curr;
+        }
+    }
+    if (calculated_name == "") {
+        // try an imprecise match if the exact matching didn't work.
+        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+            string curr = llList2String(_private_global_buttons, indy);
+            if (is_prefix(curr, message)) {
+                // correct the answer based on the full button string.
+                calculated_name = curr;
+            }
+        }
+    }
+    if (calculated_name != "") {
+        // only send a response if that menu choice made sense to us.
+        send_reply(LINK_THIS, MENUTINI_HUFFWARE_ID + REPLY_DISTANCE,
+            [ global_menu_name, calculated_name, _private_global_av_key ],
+            SHOW_MENU_COMMAND);
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+//////////////
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//hmmm: extract this code to a menutini example!
+
+//////////////
+// how to invoke a menu (assuming menutini is in same prim as calling script):
+//
+list buttons;  // holds onto the set of menu options.
+//
+integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
+//
+example_invocation()
+{
+    string menu_name = "grumfazoid";
+    string title = "These united colors of ben's futon have unfortunately run.";
+    buttons = [ "garp out", "sklonar", "fuzzlenog" ];
+    integer menu_channel = random_channel();
+    key listen_to = llGetOwner();
+    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
+        menu_name + HUFFWARE_PARM_SEPARATOR
+        + title + HUFFWARE_PARM_SEPARATOR
+        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
+        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
+        + (string)listen_to);
+}
+//
+// how to handle the response message when the user chooses a button.
+//
+react_to_menu(string menu_name, string which_choice)
+{
+    // one might use the menu_name when dealing with multiple different menus.
+
+    integer indy = 0;
+    // find the specified item and process it.
+    while (indy < llGetListLength(buttons)) {
+        // see if the current destination matches.
+        if (llSubStringIndex(llList2String(buttons, indy), which_choice) == 0) {
+            // this is the chosen item.
+//            process_menu_item(indy);  // using numerical numbering.
+// this function must be implemented in your own code; it is what handles the
+// user picking a particular button on the menu.
+            return;            
+        }
+        indy++;
+    }
+    llSay(0, "did not find menu option");
+}
+
+// an example for menu handling.  this gets the response from menutini library
+// and calls the menu processing method "react_to_menu".
+example_handle_link_message(integer sender, integer num, string msg, key id)
+{
+    if (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) return;  // not for us.
+    if (msg != SHOW_MENU_COMMAND) return;  // also not for us.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string menu_name = llList2String(parms, 0);
+    string which_choice = llList2String(parms, 1);
+    react_to_menu(menu_name, which_choice);
+}
+
+// then inside a state, you need an event handler like so:
+//
+// link_message(integer sender, integer num, string msg, key id)
+// { example_handle_link_message(sender, num, msg, id); }
+
+//
+// end invocation sample code...
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); }
+
+    link_message(integer sender, integer huff_id, string msg, key id)
+    { handle_link_message(sender, huff_id, msg, id); }
+
+    listen(integer channel, string name, key id, string message)
+    { process_menu_response(channel, name, id, message); }
+    
+    // if the timer goes off, then the user has ignored the menu for longer than the
+    // timeout.  we need to turn off our listen and ignore that menu.
+    timer() { clear_menu(); }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/menutini_library_v5.9.txt b/huffware/huffotronic_jaunter_updater_v5.1/menutini_library_v5.9.txt
deleted file mode 100755 (executable)
index abd2711..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-
-// huffware script: menutini library, by fred huffhines.
-//
-// this is a library script for menuing that provides a way to remote control the
-// menu, somewhat.  another script can zing link messages at this script and a menu
-// will be shown based on the specified description and buttons.  when the user
-// selects an answer, that result is sent back in a link message reply.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// useful constants you might want to change:
-
-integer TIMEOUT_FOR_MENU = 42;
-    // timeout for the menu in seconds.
-//hmmm: may want this to be selectable from menu request.
-//      or may even want to never time out!
-//      if we managed a list of ongoing menus, that would work.
-//      currently it cannot.
-
-integer DEBUGGING = FALSE;
-    // if this is true, then extra info will be printed when handling a menu.
-
-string NEXT_MENU_TEXT = "Next >>";
-    // what the next item will say for showing next menu page.
-
-// menutini link message API...
-//////////////
-// do not redefine these constants.
-integer MENUTINI_HUFFWARE_ID = 10009;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string SHOW_MENU_COMMAND = "#menu#";
-    // the command that tells menutini to show a menu defined by parameters
-    // that are passed along.  these must be: the menu name, the menu's title
-    // (which is really the info to show as content in the main box of the menu),
-    // the wrapped list of commands to show as menu buttons, the menu system
-    // channel's for listening, and the key to listen to.
-    // the reply will include: the menu name, the choice made and the key for
-    // the avatar.
-//
-//////////////
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-//
-//////////////
-
-// global variables...
-
-list _private_global_buttons;  // holds onto the active set of menu options.
-string _private_global_av_key;  // the key for the avatar who clicks the menu.
-string _private_global_title;  // holds onto current title text.
-
-integer _menu_base_start = 0;  // position in the items of the current menu.
-
-integer listening_id = 0;
-    // the current id of our listening for the menu.  it's an id returned by LSL
-    // that we need to track so we can cancel the listen.
-
-integer menu_system_channel = 0;
-    // messages come back to us from this channel when user clicks the dialog.
-    // this is set later and the default is meaningless.
-
-string global_menu_name = "";
-    // hangs onto the current menu's name.
-
-//hmmm: note; to manage multiple concurrent menus on different channels,
-//      we must make these into lists.  then the timeouts should apply
-//      individually to these instead of overall (if we even do timeouts;
-//      it's nicer if menus never stop being active).
-
-
-// displays the menu requested.  it's "menu_name" is an internal name that is
-// not displayed to the user.  the "title" is the content shown in the main area
-// of the menu.  "commands_in" is the list of menu items to show as buttons.
-// the "menu_channel" is where the user's clicked response will be sent.  the
-// "listen_to" key is the avatar expected to click the menu, which is needed to
-// listen to his response.
-show_menu(string menu_name, string title, list buttons,
-    integer menu_channel, key listen_to)
-{
-    // save our new parms.
-    global_menu_name = menu_name;
-    _private_global_title = title;
-    _private_global_buttons = buttons;
-    menu_system_channel = menu_channel;
-    _private_global_av_key = listen_to;
-    if (DEBUGGING) {
-        log_it("menu name: " + global_menu_name);
-        log_it("title: " + _private_global_title);
-        log_it("buttons: " + (string)buttons);
-        log_it("channel: " + (string)menu_system_channel);
-        log_it("listen key: " + (string)listen_to);
-    }
-
-    integer add_next = FALSE;  // true if we should add a next menu item.
-
-    // the math here incorporates current button position.
-    integer current = _menu_base_start;
-    integer max_buttons = llGetListLength(buttons) - current;
-
-    if (max_buttons > 12) {
-        // limitation of SL: menus have a max of 12 buttons.
-        max_buttons = 12;
-        add_next = TRUE;
-    } else if (llGetListLength(buttons) > 12) {
-        // we already have been adding next.  let's make sure this gets
-        // a wrap-around next button.
-        add_next = TRUE;
-    }
-    // chop out what we can use in a menu.
-    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
-    if (add_next) {
-        // we were asked to add a menu item for the next screen.
-        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
-    }
-
-    listening_id = llListen(menu_channel, "", listen_to, "");
-    list commands;
-    integer i;
-    // take only the prefix of the string, to avoid getting a length complaint.
-    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
-        string curr = llList2String(trunc_buttons, i);
-        integer last_pos = 23;  // default maximum, highest possible is 24.
-        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
-        curr = llGetSubString(curr, 0, last_pos);
-        commands += curr;
-    }
-    llDialog(listen_to, title, commands, menu_channel);
-    llSetTimerEvent(TIMEOUT_FOR_MENU);
-}
-
-// shuts down any connection we might have had with any active menu.  we will not
-// send any responses after this point (although we might already have responded when
-// the user clicked the menu).
-clear_menu()
-{
-    llListenRemove(listening_id);
-    llSetTimerEvent(0.0);
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-// ours do differ from normal in that we send back the channel as the number parameter
-// instead of enforcing that being MENU_HUFFWARE_ID.
-send_reply(integer destination, integer channel, list parms, string command)
-{
-    llMessageLinked(destination, channel, command,
-        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-// processes the menu requests.
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-    if (huff_id != MENUTINI_HUFFWARE_ID) return;  // not for us.
-
-    if (msg == SHOW_MENU_COMMAND) {
-        _menu_base_start = 0;  // reset the position in the menus.
-        // separate the list out.
-//log_it("id showing: " + id);
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        // toss any existing menu info.
-        clear_menu();
-//log_it("key here early: " + llList2String(parms, 4));
-        show_menu(llList2String(parms, 0), llList2String(parms, 1),
-            llParseString2List(llList2String(parms, 2),
-                [HUFFWARE_ITEM_SEPARATOR], []),
-            (integer)llList2String(parms, 3),
-            (key)llList2String(parms, 4));
-    }
-}
-
-// process the response when the user chooses a menu item.  this causes our
-// caller to be told what was selected.
-process_menu_response(integer channel, string name, key id, string message)
-{
-    if (channel != menu_system_channel) return;  // not for us.
-
-    if (message == NEXT_MENU_TEXT) {
-        // this is the special choice, so we need to go to the next page.
-        _menu_base_start += 11;
-        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
-            // we have wrapped around the list.  go to the start again.
-            _menu_base_start = 0;
-        }
-        show_menu(global_menu_name, _private_global_title,
-            _private_global_buttons, menu_system_channel,
-            _private_global_av_key);
-        return;  // handled by opening a new menu.
-    }
-    
-    string calculated_name;
-    integer indy;
-    // first try for an exact match.
-    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-        string curr = llList2String(_private_global_buttons, indy);
-        if (curr == message) {
-            // correct the answer based on the full button string.
-            calculated_name = curr;
-        }
-    }
-    if (calculated_name == "") {
-        // try an imprecise match if the exact matching didn't work.
-        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-            string curr = llList2String(_private_global_buttons, indy);
-            if (is_prefix(curr, message)) {
-                // correct the answer based on the full button string.
-                calculated_name = curr;
-            }
-        }
-    }
-    if (calculated_name != "") {
-        // only send a response if that menu choice made sense to us.
-        send_reply(LINK_THIS, MENUTINI_HUFFWARE_ID + REPLY_DISTANCE,
-            [ global_menu_name, calculated_name, _private_global_av_key ],
-            SHOW_MENU_COMMAND);
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-//////////////
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//hmmm: extract this code to a menutini example!
-
-//////////////
-// how to invoke a menu (assuming menutini is in same prim as calling script):
-//
-list buttons;  // holds onto the set of menu options.
-//
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-//
-example_invocation()
-{
-    string menu_name = "grumfazoid";
-    string title = "These united colors of ben's futon have unfortunately run.";
-    buttons = [ "garp out", "sklonar", "fuzzlenog" ];
-    integer menu_channel = random_channel();
-    key listen_to = llGetOwner();
-    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
-        menu_name + HUFFWARE_PARM_SEPARATOR
-        + title + HUFFWARE_PARM_SEPARATOR
-        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
-        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
-        + (string)listen_to);
-}
-//
-// how to handle the response message when the user chooses a button.
-//
-react_to_menu(string menu_name, string which_choice)
-{
-    // one might use the menu_name when dealing with multiple different menus.
-
-    integer indy = 0;
-    // find the specified item and process it.
-    while (indy < llGetListLength(buttons)) {
-        // see if the current destination matches.
-        if (llSubStringIndex(llList2String(buttons, indy), which_choice) == 0) {
-            // this is the chosen item.
-//            process_menu_item(indy);  // using numerical numbering.
-// this function must be implemented in your own code; it is what handles the
-// user picking a particular button on the menu.
-            return;            
-        }
-        indy++;
-    }
-    llSay(0, "did not find menu option");
-}
-
-// an example for menu handling.  this gets the response from menutini library
-// and calls the menu processing method "react_to_menu".
-example_handle_link_message(integer sender, integer num, string msg, key id)
-{
-    if (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) return;  // not for us.
-    if (msg != SHOW_MENU_COMMAND) return;  // also not for us.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string menu_name = llList2String(parms, 0);
-    string which_choice = llList2String(parms, 1);
-    react_to_menu(menu_name, which_choice);
-}
-
-// then inside a state, you need an event handler like so:
-//
-// link_message(integer sender, integer num, string msg, key id)
-// { example_handle_link_message(sender, num, msg, id); }
-
-//
-// end invocation sample code...
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); }
-
-    link_message(integer sender, integer huff_id, string msg, key id)
-    { handle_link_message(sender, huff_id, msg, id); }
-
-    listen(integer channel, string name, key id, string message)
-    { process_menu_response(channel, name, id, message); }
-    
-    // if the timer goes off, then the user has ignored the menu for longer than the
-    // timeout.  we need to turn off our listen and ignore that menu.
-    timer() { clear_menu(); }
-}
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/noteworthy_library_v12.4.lsl b/huffware/huffotronic_jaunter_updater_v5.1/noteworthy_library_v12.4.lsl
new file mode 100755 (executable)
index 0000000..4d56bac
--- /dev/null
@@ -0,0 +1,541 @@
+
+// huffware script: noteworthy library, by fred huffhines.
+//
+// a handy approach to reading a notecard.  this version supports requiring
+// a 'signature' in the notecard's first line, so that multiple notecards can
+// exist in an object without being misinterpreted.  the script is accessed via
+// its link message API, so it can be used in an object without all this code
+// needing to be embedded in another script.  it also supports queuing up requests
+// to read notecards, so multiple scripts can use it to read their specific
+// notecards without any special handling (besides waiting a bit longer).
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants that can be adapted to your needs...
+
+integer DEBUGGING = FALSE;
+    // if this is true, then a lot of extra noise is generated when notecards are read.
+
+float TIME_OUT_ON_ONE_NOTECARD = 42.0;
+    // we allow one line of a notecard this long to be read before we decide it's hosed.
+    // some sims are very very slow, and a time-out of one minute has been found lacking;
+    // we saw at least one case where the first notecard line to be read took longer than
+    // 60 seconds.  that's why we kept cranking this time-out up...
+
+// constants that should not be changed...
+
+// outcomes from handling a line in a notecard.
+integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
+integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
+integer DONE_READING = -10;  // the notecard is finished being read.
+
+integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
+
+integer MAXIMUM_LINES_USED = 4;
+    // we will read this many lines at a time from the appropriate notecard.
+
+// this is the noteworthy library's API that is available via link messages.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+    
+//STRIKE THIS from everywhere.
+//string BUSY_READING_INDICATOR = "busy_already";
+//    // this return value indicates that the script is already in use by some other script.
+//    // the calling script should try again later.
+
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be blank.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
+    // found) and as subsequent elements an embedded list that was read from the
+    // notecard.  this necessarily limits the size of the notecards that we can read
+    // and return.
+string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
+    // like the read notecard command, but specifies the notecard name to use.  only that
+    // specific notecard file will be consulted.  first and second parm are still signature
+    // and response code, third parm is the notecard name.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// global variables...
+
+string requested_signature = "";
+    // if this is non-empty, then it must be found in the first line of the script.
+
+integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
+
+string global_notecard_name;  // the name of the card we're reading now.
+key global_query_id = NULL_KEY;  // the identifier of our data query.
+integer current_response_code = 0;  // the code that our client uses for its reading.
+list global_query_contents;  // the lines we have read from the notecard.
+
+integer line_number = 0;  // which line are we at in notecard?
+
+integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
+
+integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
+
+list pending_signatures;  // signatures from queued requests for reading.
+list pending_response_codes;  // response codes for the queued requests.
+list pending_notecard_names;  // card names if it's a specific request.
+
+//////////////
+
+startup_initialize()
+{
+    pending_signatures = [];
+    pending_response_codes = [];
+    pending_notecard_names = [];
+    current_response_code = 0;
+    llSetTimerEvent(0.0);
+}
+
+reset_for_reading(string signature, integer response_code)
+{
+    requested_signature = signature;
+    current_response_code = response_code;
+    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
+    global_query_contents = [];
+    global_notecard_name = "";
+    line_number = 0;
+    found_signature_line = FALSE;
+    trying_notecard_at = -1;
+    global_query_id = NULL_KEY;
+}
+
+// use the existing global notecard setting to start reading.
+select_specific_notecard()
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    line_number = 0;  // reset line number again.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// picks the notecard at the "index" (from 0 to num_notecards - 1) and
+// starts reading it.
+select_notecard(integer index)
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
+    if (card_specified == "") return;   // not good.  bad index.
+    global_notecard_name = card_specified;
+    line_number = 0;  // reset line number again.
+    // we have a new file name, so load up the destinations, hopefully.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// increments our index in the count of notecards that the object has, and start
+// reading the next notecard (at the index).
+integer try_next_notecard()
+{
+    if (only_read_one_notecard) {
+        return FALSE;  // we were only going to try one.
+    }
+    // reset some values that might have applied before.
+    global_notecard_name = "";
+    // skip to the next card.
+    trying_notecard_at++;
+    // make sure we're not over the count of cards.
+    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
+        // this is a problem.  we didn't find anything suitable.
+        return FALSE;
+    }
+    // so, now we'll try the next notecard to look for our signature.
+    select_notecard(trying_notecard_at);
+    return TRUE;
+}
+
+// process a line of text that we received from the current notecard.
+integer handle_notecard_line(key query_id, string data)
+{
+    // if we're not at the end of the notecard we're reading...
+    if (data != EOF) {
+        // there's more to read in the notecard still.
+        if (data != "") {
+            // make sure we even have a signature to look for.
+            if (!found_signature_line && (requested_signature == "")) {
+                // no signature means that we always find it.
+                found_signature_line = TRUE;
+            }
+            // did we already get our signature?  if not, see if this is it.
+            if (!found_signature_line && (data != requested_signature) ) {
+                // this is a bad notecard.  skip it.
+                if (!try_next_notecard()) {
+                    // we have no more to work with.
+                    return BAD_NOTECARD;
+                }
+                return STILL_READING;  // we'll keep going.
+            } else if (!found_signature_line && (data == requested_signature) ) {
+                // this is a good signature line, so record that and then skip it.
+                found_signature_line = TRUE;
+            } else {
+                if (DEBUGGING
+                    && ( ( (requested_signature == "") && (line_number == 0) )
+                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
+                    log_it("started reading " + global_notecard_name + "...");
+                }
+                // don't record any lines that are comments.
+                if ( (llGetSubString(data, 0, 0) != "#")
+                    && (llGetSubString(data, 0, 0) != ";") ) {
+                    // add the non-blank line to our list.
+                    global_query_contents += data;
+                    // make sure we still have enough space to keep going.
+                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
+                        // ooh, make sure we pause before blowing our heap&stack.
+                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
+                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
+                    }
+                }
+            }
+        }
+        line_number++;  // increase the line count.
+        // reset the timer rather than timing out, if we actually got some data.
+        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
+        // request the next line from the notecard.
+        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
+        if (global_query_id == NULL_KEY) {
+//log_it("failed to restart notecard reading.");
+            return DONE_READING;
+//is that the best outcome?
+        }
+        return STILL_READING;
+    } else {
+        // that's the end of the notecard.  we need some minimal verification that it
+        // wasn't full of garbage.
+        if (!found_signature_line) {
+            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
+            if (!try_next_notecard()) {
+                return BAD_NOTECARD;  // we failed to find a good line?
+            } else {
+                // the next notecard's coming through now.
+                return STILL_READING;
+            }
+        } else {
+//            if (DEBUGGING) log_it("found signature.");
+            // saw the signature line, so this is a good one.
+            return DONE_READING;
+        }
+    }
+}
+
+// only sends reply; does not reset notecard process.
+send_reply(integer destination, list parms, string command,
+    integer include_query)
+{
+//integer items = llGetListLength(parms);
+//if (include_query) items += llGetListLength(global_query_contents);
+//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
+
+   if (!include_query) {
+        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+    } else {
+        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command,
+            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
+    }
+    global_query_contents = [];
+//log_it("post-sending, mem=" + (string)llGetFreeMemory());
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply_and_reset(integer destination, list parms, string command,
+    integer include_query)
+{
+    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
+    send_reply(destination, parms, command, include_query);
+    current_response_code = 0;  // reset back to default so we can start another read.
+    global_query_id = NULL_KEY;  // reset so we accept no more data.
+}
+
+// if there are other pending notecard reads, this goes to the next one listed.
+dequeue_next_request()
+{
+    if (llGetListLength(pending_signatures)) {
+        // get the info from the next pending item.
+        string sig = llList2String(pending_signatures, 0);
+        integer response_code = llList2Integer(pending_response_codes, 0);
+        string notecard = llList2String(pending_notecard_names, 0);
+        // whack the head of the queue since we grabbed the info.
+        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
+        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
+        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
+        if (llStringLength(notecard)) {
+            global_notecard_name = notecard;
+            select_specific_notecard();
+        } else {
+            reset_for_reading(sig, response_code);
+        }
+    }
+}
+
+// deals with one data server answer from the notecard.
+process_notecard_line(key query_id, string data)
+{
+    // try to consume a line from the notecard.
+    integer outcome = handle_notecard_line(query_id, data);
+    if (outcome == DONE_READING) {
+        // that was a valid notecard and we read all of it.
+        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
+        // send back the results.
+        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
+            READ_NOTECARD_COMMAND, TRUE);
+    } else if (outcome == BAD_NOTECARD) {
+        // bail; this problem must be addressed by other means.
+        if (DEBUGGING) log_it("failed to find an appropriate notecard");
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    } else if (outcome == STILL_READING) {
+        // we have a good card and are still processing it.
+        return;
+    } else {
+        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
+        // again, bail out.  we have no idea what happened with this.
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    }
+    // if we have reached here, we should crank up the next queued notecard reading.
+    dequeue_next_request();
+}
+
+// processes requests from our users.
+handle_link_message(integer which, integer num, string msg, key id)
+{
+    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
+
+    if (msg == READ_NOTECARD_COMMAND) {
+        only_read_one_notecard = FALSE;  // general inquiry for any card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read notecard--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code = llList2Integer(parms, 1);
+//log_it("got signature " + signature + " and respcode " + (string)response_code);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code);
+            if (!try_next_notecard()) {
+                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
+                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code ],
+                    READ_NOTECARD_COMMAND, FALSE);
+                return;
+            }
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code;
+//holding:            pending_notecard_names += "";
+//holding:        }
+    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
+        only_read_one_notecard = TRUE;  // they want one particular card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read specific--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code = llList2Integer(parms, 1);
+        string notecard_name = llList2String(parms, 2);
+//log_it("got signature " + signature + " and respcode " + (string)response_code);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code);
+            global_notecard_name = notecard_name;  // set our global.
+            select_specific_notecard();
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code;
+//holding:            pending_notecard_names += notecard_name;
+//holding:        }
+    }
+}
+
+
+///////////////
+
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.4.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        startup_initialize();
+    }
+    
+    state_exit() {
+        llSetTimerEvent(0);
+    }
+    
+    // we don't do anything until we're given a command to read a notecard.
+    link_message(integer which, integer num, string msg, key id) 
+    {
+        if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
+        handle_link_message(which, num, msg, id);
+    }
+    
+    on_rez(integer parm) { state rerun; }
+    
+    timer() {
+        llSetTimerEvent(0.0);  // stop any timer now.
+        // let the caller know this has failed out.
+//        if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+        current_response_code = 0;  // we gave up on that one.
+        dequeue_next_request();  // get next reading started if we have anything to read.
+    }
+
+    dataserver(key query_id, string data) {
+        // make sure this data is for us.
+        if (global_query_id != query_id) return;
+        // yep, seems to be.
+        process_notecard_line(query_id, data);
+    }
+}
+
+
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/noteworthy_library_v12.4.txt b/huffware/huffotronic_jaunter_updater_v5.1/noteworthy_library_v12.4.txt
deleted file mode 100755 (executable)
index 4d56bac..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-
-// huffware script: noteworthy library, by fred huffhines.
-//
-// a handy approach to reading a notecard.  this version supports requiring
-// a 'signature' in the notecard's first line, so that multiple notecards can
-// exist in an object without being misinterpreted.  the script is accessed via
-// its link message API, so it can be used in an object without all this code
-// needing to be embedded in another script.  it also supports queuing up requests
-// to read notecards, so multiple scripts can use it to read their specific
-// notecards without any special handling (besides waiting a bit longer).
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants that can be adapted to your needs...
-
-integer DEBUGGING = FALSE;
-    // if this is true, then a lot of extra noise is generated when notecards are read.
-
-float TIME_OUT_ON_ONE_NOTECARD = 42.0;
-    // we allow one line of a notecard this long to be read before we decide it's hosed.
-    // some sims are very very slow, and a time-out of one minute has been found lacking;
-    // we saw at least one case where the first notecard line to be read took longer than
-    // 60 seconds.  that's why we kept cranking this time-out up...
-
-// constants that should not be changed...
-
-// outcomes from handling a line in a notecard.
-integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
-integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
-integer DONE_READING = -10;  // the notecard is finished being read.
-
-integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
-
-integer MAXIMUM_LINES_USED = 4;
-    // we will read this many lines at a time from the appropriate notecard.
-
-// this is the noteworthy library's API that is available via link messages.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-    
-//STRIKE THIS from everywhere.
-//string BUSY_READING_INDICATOR = "busy_already";
-//    // this return value indicates that the script is already in use by some other script.
-//    // the calling script should try again later.
-
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be blank.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
-    // found) and as subsequent elements an embedded list that was read from the
-    // notecard.  this necessarily limits the size of the notecards that we can read
-    // and return.
-string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
-    // like the read notecard command, but specifies the notecard name to use.  only that
-    // specific notecard file will be consulted.  first and second parm are still signature
-    // and response code, third parm is the notecard name.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// global variables...
-
-string requested_signature = "";
-    // if this is non-empty, then it must be found in the first line of the script.
-
-integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
-
-string global_notecard_name;  // the name of the card we're reading now.
-key global_query_id = NULL_KEY;  // the identifier of our data query.
-integer current_response_code = 0;  // the code that our client uses for its reading.
-list global_query_contents;  // the lines we have read from the notecard.
-
-integer line_number = 0;  // which line are we at in notecard?
-
-integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
-
-integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
-
-list pending_signatures;  // signatures from queued requests for reading.
-list pending_response_codes;  // response codes for the queued requests.
-list pending_notecard_names;  // card names if it's a specific request.
-
-//////////////
-
-startup_initialize()
-{
-    pending_signatures = [];
-    pending_response_codes = [];
-    pending_notecard_names = [];
-    current_response_code = 0;
-    llSetTimerEvent(0.0);
-}
-
-reset_for_reading(string signature, integer response_code)
-{
-    requested_signature = signature;
-    current_response_code = response_code;
-    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
-    global_query_contents = [];
-    global_notecard_name = "";
-    line_number = 0;
-    found_signature_line = FALSE;
-    trying_notecard_at = -1;
-    global_query_id = NULL_KEY;
-}
-
-// use the existing global notecard setting to start reading.
-select_specific_notecard()
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    line_number = 0;  // reset line number again.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// picks the notecard at the "index" (from 0 to num_notecards - 1) and
-// starts reading it.
-select_notecard(integer index)
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
-    if (card_specified == "") return;   // not good.  bad index.
-    global_notecard_name = card_specified;
-    line_number = 0;  // reset line number again.
-    // we have a new file name, so load up the destinations, hopefully.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// increments our index in the count of notecards that the object has, and start
-// reading the next notecard (at the index).
-integer try_next_notecard()
-{
-    if (only_read_one_notecard) {
-        return FALSE;  // we were only going to try one.
-    }
-    // reset some values that might have applied before.
-    global_notecard_name = "";
-    // skip to the next card.
-    trying_notecard_at++;
-    // make sure we're not over the count of cards.
-    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
-        // this is a problem.  we didn't find anything suitable.
-        return FALSE;
-    }
-    // so, now we'll try the next notecard to look for our signature.
-    select_notecard(trying_notecard_at);
-    return TRUE;
-}
-
-// process a line of text that we received from the current notecard.
-integer handle_notecard_line(key query_id, string data)
-{
-    // if we're not at the end of the notecard we're reading...
-    if (data != EOF) {
-        // there's more to read in the notecard still.
-        if (data != "") {
-            // make sure we even have a signature to look for.
-            if (!found_signature_line && (requested_signature == "")) {
-                // no signature means that we always find it.
-                found_signature_line = TRUE;
-            }
-            // did we already get our signature?  if not, see if this is it.
-            if (!found_signature_line && (data != requested_signature) ) {
-                // this is a bad notecard.  skip it.
-                if (!try_next_notecard()) {
-                    // we have no more to work with.
-                    return BAD_NOTECARD;
-                }
-                return STILL_READING;  // we'll keep going.
-            } else if (!found_signature_line && (data == requested_signature) ) {
-                // this is a good signature line, so record that and then skip it.
-                found_signature_line = TRUE;
-            } else {
-                if (DEBUGGING
-                    && ( ( (requested_signature == "") && (line_number == 0) )
-                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
-                    log_it("started reading " + global_notecard_name + "...");
-                }
-                // don't record any lines that are comments.
-                if ( (llGetSubString(data, 0, 0) != "#")
-                    && (llGetSubString(data, 0, 0) != ";") ) {
-                    // add the non-blank line to our list.
-                    global_query_contents += data;
-                    // make sure we still have enough space to keep going.
-                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
-                        // ooh, make sure we pause before blowing our heap&stack.
-                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
-                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
-                    }
-                }
-            }
-        }
-        line_number++;  // increase the line count.
-        // reset the timer rather than timing out, if we actually got some data.
-        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
-        // request the next line from the notecard.
-        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
-        if (global_query_id == NULL_KEY) {
-//log_it("failed to restart notecard reading.");
-            return DONE_READING;
-//is that the best outcome?
-        }
-        return STILL_READING;
-    } else {
-        // that's the end of the notecard.  we need some minimal verification that it
-        // wasn't full of garbage.
-        if (!found_signature_line) {
-            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
-            if (!try_next_notecard()) {
-                return BAD_NOTECARD;  // we failed to find a good line?
-            } else {
-                // the next notecard's coming through now.
-                return STILL_READING;
-            }
-        } else {
-//            if (DEBUGGING) log_it("found signature.");
-            // saw the signature line, so this is a good one.
-            return DONE_READING;
-        }
-    }
-}
-
-// only sends reply; does not reset notecard process.
-send_reply(integer destination, list parms, string command,
-    integer include_query)
-{
-//integer items = llGetListLength(parms);
-//if (include_query) items += llGetListLength(global_query_contents);
-//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
-
-   if (!include_query) {
-        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-    } else {
-        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command,
-            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
-    }
-    global_query_contents = [];
-//log_it("post-sending, mem=" + (string)llGetFreeMemory());
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply_and_reset(integer destination, list parms, string command,
-    integer include_query)
-{
-    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
-    send_reply(destination, parms, command, include_query);
-    current_response_code = 0;  // reset back to default so we can start another read.
-    global_query_id = NULL_KEY;  // reset so we accept no more data.
-}
-
-// if there are other pending notecard reads, this goes to the next one listed.
-dequeue_next_request()
-{
-    if (llGetListLength(pending_signatures)) {
-        // get the info from the next pending item.
-        string sig = llList2String(pending_signatures, 0);
-        integer response_code = llList2Integer(pending_response_codes, 0);
-        string notecard = llList2String(pending_notecard_names, 0);
-        // whack the head of the queue since we grabbed the info.
-        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
-        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
-        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
-        if (llStringLength(notecard)) {
-            global_notecard_name = notecard;
-            select_specific_notecard();
-        } else {
-            reset_for_reading(sig, response_code);
-        }
-    }
-}
-
-// deals with one data server answer from the notecard.
-process_notecard_line(key query_id, string data)
-{
-    // try to consume a line from the notecard.
-    integer outcome = handle_notecard_line(query_id, data);
-    if (outcome == DONE_READING) {
-        // that was a valid notecard and we read all of it.
-        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
-        // send back the results.
-        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
-            READ_NOTECARD_COMMAND, TRUE);
-    } else if (outcome == BAD_NOTECARD) {
-        // bail; this problem must be addressed by other means.
-        if (DEBUGGING) log_it("failed to find an appropriate notecard");
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    } else if (outcome == STILL_READING) {
-        // we have a good card and are still processing it.
-        return;
-    } else {
-        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
-        // again, bail out.  we have no idea what happened with this.
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    }
-    // if we have reached here, we should crank up the next queued notecard reading.
-    dequeue_next_request();
-}
-
-// processes requests from our users.
-handle_link_message(integer which, integer num, string msg, key id)
-{
-    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
-
-    if (msg == READ_NOTECARD_COMMAND) {
-        only_read_one_notecard = FALSE;  // general inquiry for any card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read notecard--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code = llList2Integer(parms, 1);
-//log_it("got signature " + signature + " and respcode " + (string)response_code);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code);
-            if (!try_next_notecard()) {
-                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
-                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code ],
-                    READ_NOTECARD_COMMAND, FALSE);
-                return;
-            }
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code;
-//holding:            pending_notecard_names += "";
-//holding:        }
-    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
-        only_read_one_notecard = TRUE;  // they want one particular card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read specific--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code = llList2Integer(parms, 1);
-        string notecard_name = llList2String(parms, 2);
-//log_it("got signature " + signature + " and respcode " + (string)response_code);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code);
-            global_notecard_name = notecard_name;  // set our global.
-            select_specific_notecard();
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code;
-//holding:            pending_notecard_names += notecard_name;
-//holding:        }
-    }
-}
-
-
-///////////////
-
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.4.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        startup_initialize();
-    }
-    
-    state_exit() {
-        llSetTimerEvent(0);
-    }
-    
-    // we don't do anything until we're given a command to read a notecard.
-    link_message(integer which, integer num, string msg, key id) 
-    {
-        if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
-        handle_link_message(which, num, msg, id);
-    }
-    
-    on_rez(integer parm) { state rerun; }
-    
-    timer() {
-        llSetTimerEvent(0.0);  // stop any timer now.
-        // let the caller know this has failed out.
-//        if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-        current_response_code = 0;  // we gave up on that one.
-        dequeue_next_request();  // get next reading started if we have anything to read.
-    }
-
-    dataserver(key query_id, string data) {
-        // make sure this data is for us.
-        if (global_query_id != query_id) return;
-        // yep, seems to be.
-        process_notecard_line(query_id, data);
-    }
-}
-
-
-
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/texture_mover_v3.0.lsl b/huffware/huffotronic_jaunter_updater_v5.1/texture_mover_v3.0.lsl
new file mode 100755 (executable)
index 0000000..57a1e64
--- /dev/null
@@ -0,0 +1,237 @@
+
+// huffware script: texture mover, by fred huffhines
+//
+// moves a texture across the object, either by smooth animation or brute force offsetting.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants...
+
+integer USE_TEXTURE_ANIMATION = TRUE;
+    // by default, we use texture animation which is a lower-lag way to
+    // make the texture move.  if this is false, then we use a timed update
+    // to move the texture instead.
+    // note: these modes are actually really different.  the texture animation
+    // is included here because i wanted to smooth out some objects that used
+    // texture movement.
+
+// used in both types...
+
+float TIMER_INTERVAL = 0.2;  // how fast do we move texture?
+
+// for timed movement...
+
+vector OFFSET_MOVEMENT = ZERO_VECTOR;  // no movement.
+//vector OFFSET_MOVEMENT = <0.0, -0.02, 0.0>;
+    // how much to move the texture by in x,y,z directions.
+
+//float OFFSET_ROTATION = 0.0;  // in degrees.
+float OFFSET_ROTATION = -1.0;  // in degrees.
+
+// for texture animations...
+
+float MOVER_TIMER_DIVISOR = 30.0;
+    // makes the movement comparable to timed method.
+
+float ROTATER_TIMER_DIVISOR = 7.0;
+    // makes the rotation comparable to timed method.
+
+// iterative movement of texture.
+move_texture(vector offset)
+{
+    vector current = llGetTextureOffset(ALL_SIDES);
+    current += offset;
+    if (current.x > 1.0) current.x = -1.0;
+    if (current.x < -1.0) current.x = 1.0;
+    if (current.y > 1.0) current.y = -1.0;
+    if (current.y < -1.0) current.y = 1.0;
+    llOffsetTexture(current.x, current.y, ALL_SIDES);
+}
+
+// iterative rotation of texture.  "spin" is measured in degrees.
+spin_texture(float spin)
+{
+    float rot = llGetTextureRot(ALL_SIDES);  // get our current state.
+    rot += spin * DEG_TO_RAD;  // add some rotation.
+    llRotateTexture(rot, ALL_SIDES); //rotate the object   
+}
+
+initialize_texture_mover()
+{
+    if (!USE_TEXTURE_ANIMATION) {
+        // we're stuck with the timed update style for movement.
+        llSetTimerEvent(TIMER_INTERVAL);
+        // turn off previous animation.
+        llSetTextureAnim(0, ALL_SIDES, 0, 0, 0, 0, 0);
+    } else {
+        // we can just set the texture movement here and be done with it.
+        integer x_frames = 1;
+        integer y_frames = 1;
+        llSetTimerEvent(0);  // we don't use a timer.
+
+//hmmm: how do we combine rotation and offsets?  currently mutually exclusive.
+
+        if (OFFSET_MOVEMENT != ZERO_VECTOR) {
+            float timer_interval = TIMER_INTERVAL / MOVER_TIMER_DIVISOR;
+log_it("getting x_frames=" + (string)x_frames
++ " y_frames=" + (string)y_frames
++ " timer_intvl=" + (string)timer_interval);
+
+            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES,
+                x_frames, y_frames,
+                0, 100, timer_interval);
+        } else if (OFFSET_ROTATION != 0.0) {
+            float timer_interval = TIMER_INTERVAL / ROTATER_TIMER_DIVISOR;
+            // we're actually not using the rotation at all here, except for
+            // the sign.  that seems pretty busted.
+            if (OFFSET_ROTATION < 0) timer_interval *= -1.0;
+            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE, ALL_SIDES,
+                0, 0,
+                0, TWO_PI, timer_interval);
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+//
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        initialize_texture_mover();
+    }
+
+    timer() {
+        // the timed approach is the only one so far that allows both a
+        // movement of the texture and a rotation.
+        if (OFFSET_MOVEMENT != ZERO_VECTOR) move_texture(OFFSET_MOVEMENT);
+        if (OFFSET_ROTATION != 0.0) spin_texture(OFFSET_ROTATION);
+    }
+}
+
diff --git a/huffware/huffotronic_jaunter_updater_v5.1/texture_mover_v3.0.txt b/huffware/huffotronic_jaunter_updater_v5.1/texture_mover_v3.0.txt
deleted file mode 100755 (executable)
index 57a1e64..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-
-// huffware script: texture mover, by fred huffhines
-//
-// moves a texture across the object, either by smooth animation or brute force offsetting.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants...
-
-integer USE_TEXTURE_ANIMATION = TRUE;
-    // by default, we use texture animation which is a lower-lag way to
-    // make the texture move.  if this is false, then we use a timed update
-    // to move the texture instead.
-    // note: these modes are actually really different.  the texture animation
-    // is included here because i wanted to smooth out some objects that used
-    // texture movement.
-
-// used in both types...
-
-float TIMER_INTERVAL = 0.2;  // how fast do we move texture?
-
-// for timed movement...
-
-vector OFFSET_MOVEMENT = ZERO_VECTOR;  // no movement.
-//vector OFFSET_MOVEMENT = <0.0, -0.02, 0.0>;
-    // how much to move the texture by in x,y,z directions.
-
-//float OFFSET_ROTATION = 0.0;  // in degrees.
-float OFFSET_ROTATION = -1.0;  // in degrees.
-
-// for texture animations...
-
-float MOVER_TIMER_DIVISOR = 30.0;
-    // makes the movement comparable to timed method.
-
-float ROTATER_TIMER_DIVISOR = 7.0;
-    // makes the rotation comparable to timed method.
-
-// iterative movement of texture.
-move_texture(vector offset)
-{
-    vector current = llGetTextureOffset(ALL_SIDES);
-    current += offset;
-    if (current.x > 1.0) current.x = -1.0;
-    if (current.x < -1.0) current.x = 1.0;
-    if (current.y > 1.0) current.y = -1.0;
-    if (current.y < -1.0) current.y = 1.0;
-    llOffsetTexture(current.x, current.y, ALL_SIDES);
-}
-
-// iterative rotation of texture.  "spin" is measured in degrees.
-spin_texture(float spin)
-{
-    float rot = llGetTextureRot(ALL_SIDES);  // get our current state.
-    rot += spin * DEG_TO_RAD;  // add some rotation.
-    llRotateTexture(rot, ALL_SIDES); //rotate the object   
-}
-
-initialize_texture_mover()
-{
-    if (!USE_TEXTURE_ANIMATION) {
-        // we're stuck with the timed update style for movement.
-        llSetTimerEvent(TIMER_INTERVAL);
-        // turn off previous animation.
-        llSetTextureAnim(0, ALL_SIDES, 0, 0, 0, 0, 0);
-    } else {
-        // we can just set the texture movement here and be done with it.
-        integer x_frames = 1;
-        integer y_frames = 1;
-        llSetTimerEvent(0);  // we don't use a timer.
-
-//hmmm: how do we combine rotation and offsets?  currently mutually exclusive.
-
-        if (OFFSET_MOVEMENT != ZERO_VECTOR) {
-            float timer_interval = TIMER_INTERVAL / MOVER_TIMER_DIVISOR;
-log_it("getting x_frames=" + (string)x_frames
-+ " y_frames=" + (string)y_frames
-+ " timer_intvl=" + (string)timer_interval);
-
-            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES,
-                x_frames, y_frames,
-                0, 100, timer_interval);
-        } else if (OFFSET_ROTATION != 0.0) {
-            float timer_interval = TIMER_INTERVAL / ROTATER_TIMER_DIVISOR;
-            // we're actually not using the rotation at all here, except for
-            // the sign.  that seems pretty busted.
-            if (OFFSET_ROTATION < 0) timer_interval *= -1.0;
-            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE, ALL_SIDES,
-                0, 0,
-                0, TWO_PI, timer_interval);
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-//
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        initialize_texture_mover();
-    }
-
-    timer() {
-        // the timed approach is the only one so far that allows both a
-        // movement of the texture and a rotation.
-        if (OFFSET_MOVEMENT != ZERO_VECTOR) move_texture(OFFSET_MOVEMENT);
-        if (OFFSET_ROTATION != 0.0) spin_texture(OFFSET_ROTATION);
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/Hour_Hand_v0.5.lsl b/huffware/huffotronic_tools_n_testers_v6.1/Hour_Hand_v0.5.lsl
new file mode 100755 (executable)
index 0000000..7027c39
--- /dev/null
@@ -0,0 +1,109 @@
+
+// huffware script: hour hand, modified by fred huffhines.
+// 
+// expanded to support time zones by fred huffhines, december 2009.
+//
+// noticed this in arcadia asylum's great hobo cuckoo clock.
+// this script is licensed by Beezle Warburton:
+//    "I released those 'into the wild' years ago,do what you like,
+//     I just ask that people don't resell the scripts by themselves."
+//
+// fred's changes licensed by:
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+
+// Optional second hand will be a much simpler script that will be
+// unrelated to real-time.
+//
+// note - to reduce load, this script only calculates once a minute, so
+// this provides a jump style minute hand, rather than a smoothy rotating one.
+// This (and rounding) makes the clock's accuracy +/- 1 minute.
+// It's a prim clock anyways, so digital accuracy is just excessive.
+//
+// It would probably be more elegant to use link messages rather than each
+// hand having it's own script, however, this method allows for less caution
+// when linking/unlinking parts of the clock.
+
+// To not mess up timekeeping, please keep chime sounds under 4 seconds long.
+
+integer time;
+integer hours;
+integer minutes;
+
+float anglehours;
+float angleminutes;
+
+integer chime;
+integer numrings;
+
+string chimesound = "CuckooClock";
+float chimevolume = 1.0;
+
+// this is what might be adjusted.
+integer LOCAL_TIME_ZONE_OFFSET = -5;  //-5 is EST, -8 is PST.
+
+// the code used in linked messages for us.
+integer SECRET_TIME_ZONE_ADJUSTER_ID = -2091823;
+string TIME_ZONE_ADJUST_COMMAND = "tzadjust";
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        // we want to calculate once a minute.
+        llSetTimerEvent(60.0);
+    }
+    timer() {
+        llSetTimerEvent(0);
+        time = (integer)llGetGMTclock(); // seconds since midnight
+        // adjust the hours for the time zone.  this will work for most time zones that
+        // go through daylight saving time, like the pacific zone where SL is rooted.
+        hours = (time / 3600) + LOCAL_TIME_ZONE_OFFSET;
+        // convert from 24 to 12 hour time
+        if (hours > 11) {
+            hours = hours - 12;
+        } else if (hours < 0) {
+            hours = hours + 12;
+        }
+        minutes = (time % 3600) / 60;
+        
+        numrings = (integer)hours;
+        if (numrings == 0) {
+            numrings = 12;
+        }
+        
+        // the extra addition here makes a smooth hour hand
+        // for example, at 6:30, the hour hand should actually
+        // be halfway between 6 and 7 on the clock dial
+        
+        anglehours = - (((float)hours / 12) + (((float)minutes / 720))) * TWO_PI;
+//incompatible with opensim:        llSetSoundQueueing(TRUE);
+        llRotateTexture(anglehours, ALL_SIDES);
+        if (minutes == 0) {
+            llMessageLinked(-1,numrings,"chime",NULL_KEY);
+            //for (chime = 0; chime < numrings; chime++) {
+            //      llPlaySound(chimesound, chimevolume);
+            //      llSleep(3.0);    
+            //}            
+        }
+        llSetTimerEvent(60.0);
+    }
+    
+    link_message(integer sender, integer num, string msg, key id) {
+        if ( (num != SECRET_TIME_ZONE_ADJUSTER_ID) || (msg != TIME_ZONE_ADJUST_COMMAND) )
+            return;  // not for us.
+        // this should be a time zone for us to use.
+        LOCAL_TIME_ZONE_OFFSET = (integer)((string)id);
+//llSay(0, "got a new time zone of " + (string)LOCAL_TIME_ZONE_OFFSET );
+        // handle this update as soon as possible.
+        llSetTimerEvent(0.1);
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/Hour_Hand_v0.5.txt b/huffware/huffotronic_tools_n_testers_v6.1/Hour_Hand_v0.5.txt
deleted file mode 100755 (executable)
index 7027c39..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-
-// huffware script: hour hand, modified by fred huffhines.
-// 
-// expanded to support time zones by fred huffhines, december 2009.
-//
-// noticed this in arcadia asylum's great hobo cuckoo clock.
-// this script is licensed by Beezle Warburton:
-//    "I released those 'into the wild' years ago,do what you like,
-//     I just ask that people don't resell the scripts by themselves."
-//
-// fred's changes licensed by:
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-
-// Optional second hand will be a much simpler script that will be
-// unrelated to real-time.
-//
-// note - to reduce load, this script only calculates once a minute, so
-// this provides a jump style minute hand, rather than a smoothy rotating one.
-// This (and rounding) makes the clock's accuracy +/- 1 minute.
-// It's a prim clock anyways, so digital accuracy is just excessive.
-//
-// It would probably be more elegant to use link messages rather than each
-// hand having it's own script, however, this method allows for less caution
-// when linking/unlinking parts of the clock.
-
-// To not mess up timekeeping, please keep chime sounds under 4 seconds long.
-
-integer time;
-integer hours;
-integer minutes;
-
-float anglehours;
-float angleminutes;
-
-integer chime;
-integer numrings;
-
-string chimesound = "CuckooClock";
-float chimevolume = 1.0;
-
-// this is what might be adjusted.
-integer LOCAL_TIME_ZONE_OFFSET = -5;  //-5 is EST, -8 is PST.
-
-// the code used in linked messages for us.
-integer SECRET_TIME_ZONE_ADJUSTER_ID = -2091823;
-string TIME_ZONE_ADJUST_COMMAND = "tzadjust";
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        // we want to calculate once a minute.
-        llSetTimerEvent(60.0);
-    }
-    timer() {
-        llSetTimerEvent(0);
-        time = (integer)llGetGMTclock(); // seconds since midnight
-        // adjust the hours for the time zone.  this will work for most time zones that
-        // go through daylight saving time, like the pacific zone where SL is rooted.
-        hours = (time / 3600) + LOCAL_TIME_ZONE_OFFSET;
-        // convert from 24 to 12 hour time
-        if (hours > 11) {
-            hours = hours - 12;
-        } else if (hours < 0) {
-            hours = hours + 12;
-        }
-        minutes = (time % 3600) / 60;
-        
-        numrings = (integer)hours;
-        if (numrings == 0) {
-            numrings = 12;
-        }
-        
-        // the extra addition here makes a smooth hour hand
-        // for example, at 6:30, the hour hand should actually
-        // be halfway between 6 and 7 on the clock dial
-        
-        anglehours = - (((float)hours / 12) + (((float)minutes / 720))) * TWO_PI;
-//incompatible with opensim:        llSetSoundQueueing(TRUE);
-        llRotateTexture(anglehours, ALL_SIDES);
-        if (minutes == 0) {
-            llMessageLinked(-1,numrings,"chime",NULL_KEY);
-            //for (chime = 0; chime < numrings; chime++) {
-            //      llPlaySound(chimesound, chimevolume);
-            //      llSleep(3.0);    
-            //}            
-        }
-        llSetTimerEvent(60.0);
-    }
-    
-    link_message(integer sender, integer num, string msg, key id) {
-        if ( (num != SECRET_TIME_ZONE_ADJUSTER_ID) || (msg != TIME_ZONE_ADJUST_COMMAND) )
-            return;  // not for us.
-        // this should be a time zone for us to use.
-        LOCAL_TIME_ZONE_OFFSET = (integer)((string)id);
-//llSay(0, "got a new time zone of " + (string)LOCAL_TIME_ZONE_OFFSET );
-        // handle this update as soon as possible.
-        llSetTimerEvent(0.1);
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/Minute_Hand_v0.4.lsl b/huffware/huffotronic_tools_n_testers_v6.1/Minute_Hand_v0.4.lsl
new file mode 100755 (executable)
index 0000000..76b517a
--- /dev/null
@@ -0,0 +1,41 @@
+
+// huffware script: minute hand, modified by fred huffhines.
+// 
+// noticed this in arcadia asylum's great hobo cuckoo clock.
+// this script is licensed by Beezle Warburton:
+//    "I released those 'into the wild' years ago,do what you like,
+//     I just ask that people don't resell the scripts by themselves."
+//
+// fred's changes licensed by:
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer time;
+integer hours;
+integer minutes;
+
+float anglehours;
+float angleminutes;
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        // we want to calculate once a minute.
+        llSetTimerEvent(60.0);
+    }
+
+    timer() {
+        time = (integer)llGetGMTclock(); // seconds since midnight
+        minutes = (time % 3600) / 60;        
+        angleminutes = -(TWO_PI * (float)minutes / 60);
+        llRotateTexture(angleminutes, ALL_SIDES);
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/Minute_Hand_v0.4.txt b/huffware/huffotronic_tools_n_testers_v6.1/Minute_Hand_v0.4.txt
deleted file mode 100755 (executable)
index 76b517a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-
-// huffware script: minute hand, modified by fred huffhines.
-// 
-// noticed this in arcadia asylum's great hobo cuckoo clock.
-// this script is licensed by Beezle Warburton:
-//    "I released those 'into the wild' years ago,do what you like,
-//     I just ask that people don't resell the scripts by themselves."
-//
-// fred's changes licensed by:
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer time;
-integer hours;
-integer minutes;
-
-float anglehours;
-float angleminutes;
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        // we want to calculate once a minute.
-        llSetTimerEvent(60.0);
-    }
-
-    timer() {
-        time = (integer)llGetGMTclock(); // seconds since midnight
-        minutes = (time % 3600) / 60;        
-        angleminutes = -(TWO_PI * (float)minutes / 60);
-        llRotateTexture(angleminutes, ALL_SIDES);
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/NC_stay_at_home_v5.2.lsl b/huffware/huffotronic_tools_n_testers_v6.1/NC_stay_at_home_v5.2.lsl
new file mode 100755 (executable)
index 0000000..60a6a3c
--- /dev/null
@@ -0,0 +1,392 @@
+
+// huffware script: stay at home, by fred huffhines
+//
+// this script attempts to keep an object at home, which is to say, near where
+// it was rezzed.  it is not perfect, and if the object quickly crosses a region
+// boundary, the object may get away.  there is an automatic termination option
+// for cases where the object is taken away and cannot get back; otherwise the
+// object will bleat its position out at regular intevals.
+// this script mainly makes sense for physical objects, since non-physical
+// objects are not as prone to being pushed around by other avatars.  in addition,
+// it really makes the most sense for an object that allows anyone to move it.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants to be adjusted as needed...
+
+float MAXIMUM_ROAMING_RANGE = 12.0;
+    // this is the farthest that we let them drag our object away, in meters.
+
+integer AUTO_TERMINATE = FALSE;
+    // if the object crosses a region boundary (exits sim, enters new one), then
+    // it will zap itself if this flag is set to true.  it will also go poof if
+    // it reaches escape velocity and travels off world.
+
+integer KEEP_IT_PHYSICAL = TRUE;
+    // if this is true, then the object's state as physical is continually
+    // refreshed.
+
+integer ROTATE_TO_TARGET = FALSE;
+    // if this is true, the object will try to rotate to a set position.
+
+integer ONLY_ROTATE_FIXED_AXES = FALSE;
+    // if this is true and rotate to target is true, then we will only try to
+    // set the rotation on the axes that are specified as "fixed" below.
+
+vector TARGETED_ROTATION = <0.0, 0.0, 0.0>;
+    // if the control rotation flag is true, the object will try to reattain
+    // this value for its rotation.
+
+// if these are set to true, the no rotation is allowed around the axis.
+// note that this decision is totally independent of whether the object has
+// a targeted rotation or not.
+integer FIXATE_X_AXIS = FALSE;
+integer FIXATE_Y_AXIS = FALSE;
+integer FIXATE_Z_AXIS = FALSE;
+
+integer MAXIMUM_FAILED_JUMPS = 200;
+    // if we are having to make this many attempts to get home, something is
+    // really wrong.  treat it like leaving the region; totally awol.
+
+float POSITION_CHECKING_INTERVAL = 8.0;
+    // how frequently the object will check where it is, in seconds.
+
+float PANIC_EVERY_N_HOURS = 4.0;
+    // this is the number of hours between panic mewling at the owner, if the object
+    // did not get told to self-terminate upon leaving the region.
+
+integer DEBUGGING = FALSE;
+    // if this is true, then the object will tell about it's problems when it
+    // goes off world or into another sim.  note that an object that is not
+    // set to auto-terminate is considered important enough to tell the owner;
+    // if you don't want to hear from lost objects, always turn on auto-terminate
+    // and turn off debugging.
+
+// these mysterious values control how the object rotates to its target.
+float ROT_STRENGTH = 1.0;
+float ROT_DAMPING = 0.25;
+//these values don't work that great, but neither did any other ones.
+//  the rotlookat stuff seems overpowered by the physical nature of an object.
+
+// global variables...
+
+vector home_place;
+    // where the object starts out inside the sim.  we will try to get back
+    // to here if we exceed our maximum distance from home.
+
+vector home_region;
+    // which sim we start out in, in terms of the region corners.  if this changes,
+    // the object has left the sim.
+
+integer homeward_jump_attempts = 0;
+    // tracks how many jumps home we've tried to make.
+
+integer last_alerted = 0;
+    // when the script last told the user about having gone missing.
+    // if this is zero, we presumably haven't been lost recently.
+
+// requires jaunting library v10.5 or greater.
+//////////////
+// do not redefine these constants.
+integer JAUNT_HUFFWARE_ID = 10008;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+// commands available via the jaunting library:
+string JAUNT_COMMAND = "#jaunt#";
+    // command used to tell jaunt script to move object.  pass a vector with the location.
+string JAUNT_LIST_COMMAND = "#jauntlist#";
+    // like regular jaunt, but expects a list of vectors as the first parameter; this list
+    // should be in the jaunter notecard format (separated by pipe characters).
+    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//
+// encases a list of vectors in the expected character for the jaunting library.
+string wrap_vector_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+//////////////
+
+// asks the jaunting library to take us to the target using a list of waypoints.
+request_jaunt(list full_journey, integer forwards)
+{
+//    jaunt_responses_awaited++;
+    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_LIST_COMMAND,
+        wrap_vector_list(full_journey) + HUFFWARE_PARM_SEPARATOR + (string)forwards);
+}
+
+// jaunts back to our home location.
+attempt_to_go_home()
+{
+    // jump back to home.
+    request_jaunt([llGetPos(), home_place], TRUE);
+}
+
+// we panic at the user this frequently, in seconds.
+float panic_interval() { return PANIC_EVERY_N_HOURS * 60.0 * 60.0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();  // make sure newest addition is only version of script.
+        // we just woke up here.  remember where we started out.
+        home_place = llGetPos();
+        home_region = llGetRegionCorner();
+        if (AUTO_TERMINATE) {
+            // make the object go kerflooey if it leaves the world entirely.
+            llSetStatus(STATUS_DIE_AT_EDGE, TRUE);
+        }
+        // disallow rotation if we were requested to.
+        llSetStatus(STATUS_ROTATE_X, !FIXATE_X_AXIS);
+        llSetStatus(STATUS_ROTATE_Y, !FIXATE_Y_AXIS);
+        llSetStatus(STATUS_ROTATE_Z, !FIXATE_Z_AXIS);
+        
+        if (ROTATE_TO_TARGET) {
+//hmmm: maybe still offer gradual form as an option also?
+            
+            // set our rotational target to the configured position.
+//            llRotTarget(llEuler2Rot(TARGETED_ROTATION), 0.01);
+            // if we're supposed to rotate, we need to start that movement
+            // towards our target rotation.
+//            llRotLookAt(llEuler2Rot(TARGETED_ROTATION), ROT_STRENGTH, ROT_DAMPING);
+        }
+        // start the timer that checks on our position.
+        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+    }
+
+    on_rez(integer parm) {
+        llResetScript();  // a cop-out; just reroutes rezzing into a script reset.
+    }
+    
+    timer() {
+
+        if (ROTATE_TO_TARGET) {
+            vector real_rot_target = TARGETED_ROTATION;
+            vector curr_rot = llRot2Euler(llGetRot());
+            
+            if (ONLY_ROTATE_FIXED_AXES) {
+                // set our rotation to the target, but only for fixed axes.
+                if (!FIXATE_X_AXIS) real_rot_target.x = curr_rot.x;
+                if (!FIXATE_Y_AXIS) real_rot_target.y = curr_rot.y;
+                if (!FIXATE_Z_AXIS) real_rot_target.z = curr_rot.z;
+            }
+
+            // see if we even need to do any rotation.
+            if (curr_rot != real_rot_target) {
+                // yes, we need to move back to the preferred rotation for at least one axis.
+                llSetStatus(STATUS_PHYSICS, FALSE);  // physics property gets fixed in next block.
+                llSetRot(llEuler2Rot(real_rot_target));
+            }
+        }
+
+        if (KEEP_IT_PHYSICAL) {
+            // remind the object that it's physical, or set it if it wasn't.  sometimes
+            // a physical object can get jinxed when bouncing into other people's lands
+            // and lose its status as a physical object.  we correct for that here.
+            llSetStatus(STATUS_PHYSICS, TRUE);
+        }
+
+        integer time_to_panic = FALSE;  // set to true if we should panic now.
+
+        // check whether the object is still in the appropriate region.
+        integer region_okay = (home_region == llGetRegionCorner());
+
+        // check to see if we're watching for a specific time.
+        if (last_alerted != 0) {
+            // ooh, we've already hit panicky conditions in the past.  let's see if
+            // it's time to tell the owner about it.
+            if (panic_interval() <= llAbs(llGetUnixTime() - last_alerted)) {
+                // time to tell them about this, oh yes.
+                time_to_panic = TRUE;
+            }
+        } else {
+            // evaluate whether we are in the right condition (right sim and
+            // without being boxed in).
+            if (!region_okay || (homeward_jump_attempts > MAXIMUM_FAILED_JUMPS)) {
+                // this is not a good situation.  we will now set the last alerted
+                // timer so as to force a panic message next time through the timer
+                // loop.
+                last_alerted = llAbs(llGetUnixTime() - (integer)panic_interval() - 1000);
+                // decide when to fire the timer next.
+                if (AUTO_TERMINATE) {
+                    llSetTimerEvent(0.1);  // fire very soon to zap.
+                } else {
+                    llSetTimerEvent(POSITION_CHECKING_INTERVAL * 5);
+                        // slow the checking down a bit, since we don't expect to
+                        // magically get back to our sim (although it could happen!).
+                }
+            }
+        }
+
+        // time to panic just means that we should tell the owner about our problematic
+        // location, or auto-terminate if configured that way.
+        if (time_to_panic) {
+            // well, we've got to say something about this dire situation.
+            string reason = "trapped by unfriendly turf";
+            if (!region_okay) reason = "crossed region boundary";
+            if (AUTO_TERMINATE) {
+                // enforce the rules; we left the building and we have no ticket back.
+                if (DEBUGGING) {
+                    llOwnerSay(reason + " -- object death -- was in "
+                        + llGetRegionName() + " at " + (string)llGetPos());
+                }
+                llDie();
+            }
+            // whew, we ducked that deadly issue.  let the owner know that we
+            // don't like this place.
+            llOwnerSay(reason + "; please come get me:\nlast in "
+                + llGetRegionName() + " at " + (string)llGetPos());
+            last_alerted = llGetUnixTime();  // reset, since we just alerted.
+            return;  // don't bother trying to move anywhere.
+        }
+        
+        if (region_okay && (last_alerted != 0) ) {
+            // hmmm, did we recover our position?
+            if (homeward_jump_attempts <= MAXIMUM_FAILED_JUMPS) {
+                // we didn't expend too many jumps, so try going home again.
+                last_alerted = 0;
+                // also go back to our normal timing cycle.
+                llSetTimerEvent(POSITION_CHECKING_INTERVAL);
+            }
+        }
+        
+        if (!region_okay || (homeward_jump_attempts > MAXIMUM_FAILED_JUMPS)
+            || (last_alerted != 0) ) {
+            // we said our piece, if any.  we can't be fuddling around here.
+            return;
+        }
+
+        // we're still in the right region, so check how far we are from the starting
+        // place.  we'll try to move back if someone dragged us too far away from it.
+        float distance = llVecDist(llGetPos(), home_place);
+        if (distance > MAXIMUM_ROAMING_RANGE) {
+            // this is not good; we need to get back to our starting point.
+            attempt_to_go_home();
+            homeward_jump_attempts++;
+        } else {
+            // reset our counter, since we are close enough to home.
+            homeward_jump_attempts = 0;
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/NC_stay_at_home_v5.2.txt b/huffware/huffotronic_tools_n_testers_v6.1/NC_stay_at_home_v5.2.txt
deleted file mode 100755 (executable)
index 60a6a3c..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-
-// huffware script: stay at home, by fred huffhines
-//
-// this script attempts to keep an object at home, which is to say, near where
-// it was rezzed.  it is not perfect, and if the object quickly crosses a region
-// boundary, the object may get away.  there is an automatic termination option
-// for cases where the object is taken away and cannot get back; otherwise the
-// object will bleat its position out at regular intevals.
-// this script mainly makes sense for physical objects, since non-physical
-// objects are not as prone to being pushed around by other avatars.  in addition,
-// it really makes the most sense for an object that allows anyone to move it.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants to be adjusted as needed...
-
-float MAXIMUM_ROAMING_RANGE = 12.0;
-    // this is the farthest that we let them drag our object away, in meters.
-
-integer AUTO_TERMINATE = FALSE;
-    // if the object crosses a region boundary (exits sim, enters new one), then
-    // it will zap itself if this flag is set to true.  it will also go poof if
-    // it reaches escape velocity and travels off world.
-
-integer KEEP_IT_PHYSICAL = TRUE;
-    // if this is true, then the object's state as physical is continually
-    // refreshed.
-
-integer ROTATE_TO_TARGET = FALSE;
-    // if this is true, the object will try to rotate to a set position.
-
-integer ONLY_ROTATE_FIXED_AXES = FALSE;
-    // if this is true and rotate to target is true, then we will only try to
-    // set the rotation on the axes that are specified as "fixed" below.
-
-vector TARGETED_ROTATION = <0.0, 0.0, 0.0>;
-    // if the control rotation flag is true, the object will try to reattain
-    // this value for its rotation.
-
-// if these are set to true, the no rotation is allowed around the axis.
-// note that this decision is totally independent of whether the object has
-// a targeted rotation or not.
-integer FIXATE_X_AXIS = FALSE;
-integer FIXATE_Y_AXIS = FALSE;
-integer FIXATE_Z_AXIS = FALSE;
-
-integer MAXIMUM_FAILED_JUMPS = 200;
-    // if we are having to make this many attempts to get home, something is
-    // really wrong.  treat it like leaving the region; totally awol.
-
-float POSITION_CHECKING_INTERVAL = 8.0;
-    // how frequently the object will check where it is, in seconds.
-
-float PANIC_EVERY_N_HOURS = 4.0;
-    // this is the number of hours between panic mewling at the owner, if the object
-    // did not get told to self-terminate upon leaving the region.
-
-integer DEBUGGING = FALSE;
-    // if this is true, then the object will tell about it's problems when it
-    // goes off world or into another sim.  note that an object that is not
-    // set to auto-terminate is considered important enough to tell the owner;
-    // if you don't want to hear from lost objects, always turn on auto-terminate
-    // and turn off debugging.
-
-// these mysterious values control how the object rotates to its target.
-float ROT_STRENGTH = 1.0;
-float ROT_DAMPING = 0.25;
-//these values don't work that great, but neither did any other ones.
-//  the rotlookat stuff seems overpowered by the physical nature of an object.
-
-// global variables...
-
-vector home_place;
-    // where the object starts out inside the sim.  we will try to get back
-    // to here if we exceed our maximum distance from home.
-
-vector home_region;
-    // which sim we start out in, in terms of the region corners.  if this changes,
-    // the object has left the sim.
-
-integer homeward_jump_attempts = 0;
-    // tracks how many jumps home we've tried to make.
-
-integer last_alerted = 0;
-    // when the script last told the user about having gone missing.
-    // if this is zero, we presumably haven't been lost recently.
-
-// requires jaunting library v10.5 or greater.
-//////////////
-// do not redefine these constants.
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-// commands available via the jaunting library:
-string JAUNT_COMMAND = "#jaunt#";
-    // command used to tell jaunt script to move object.  pass a vector with the location.
-string JAUNT_LIST_COMMAND = "#jauntlist#";
-    // like regular jaunt, but expects a list of vectors as the first parameter; this list
-    // should be in the jaunter notecard format (separated by pipe characters).
-    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//
-// encases a list of vectors in the expected character for the jaunting library.
-string wrap_vector_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-//////////////
-
-// asks the jaunting library to take us to the target using a list of waypoints.
-request_jaunt(list full_journey, integer forwards)
-{
-//    jaunt_responses_awaited++;
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_LIST_COMMAND,
-        wrap_vector_list(full_journey) + HUFFWARE_PARM_SEPARATOR + (string)forwards);
-}
-
-// jaunts back to our home location.
-attempt_to_go_home()
-{
-    // jump back to home.
-    request_jaunt([llGetPos(), home_place], TRUE);
-}
-
-// we panic at the user this frequently, in seconds.
-float panic_interval() { return PANIC_EVERY_N_HOURS * 60.0 * 60.0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();  // make sure newest addition is only version of script.
-        // we just woke up here.  remember where we started out.
-        home_place = llGetPos();
-        home_region = llGetRegionCorner();
-        if (AUTO_TERMINATE) {
-            // make the object go kerflooey if it leaves the world entirely.
-            llSetStatus(STATUS_DIE_AT_EDGE, TRUE);
-        }
-        // disallow rotation if we were requested to.
-        llSetStatus(STATUS_ROTATE_X, !FIXATE_X_AXIS);
-        llSetStatus(STATUS_ROTATE_Y, !FIXATE_Y_AXIS);
-        llSetStatus(STATUS_ROTATE_Z, !FIXATE_Z_AXIS);
-        
-        if (ROTATE_TO_TARGET) {
-//hmmm: maybe still offer gradual form as an option also?
-            
-            // set our rotational target to the configured position.
-//            llRotTarget(llEuler2Rot(TARGETED_ROTATION), 0.01);
-            // if we're supposed to rotate, we need to start that movement
-            // towards our target rotation.
-//            llRotLookAt(llEuler2Rot(TARGETED_ROTATION), ROT_STRENGTH, ROT_DAMPING);
-        }
-        // start the timer that checks on our position.
-        llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-    }
-
-    on_rez(integer parm) {
-        llResetScript();  // a cop-out; just reroutes rezzing into a script reset.
-    }
-    
-    timer() {
-
-        if (ROTATE_TO_TARGET) {
-            vector real_rot_target = TARGETED_ROTATION;
-            vector curr_rot = llRot2Euler(llGetRot());
-            
-            if (ONLY_ROTATE_FIXED_AXES) {
-                // set our rotation to the target, but only for fixed axes.
-                if (!FIXATE_X_AXIS) real_rot_target.x = curr_rot.x;
-                if (!FIXATE_Y_AXIS) real_rot_target.y = curr_rot.y;
-                if (!FIXATE_Z_AXIS) real_rot_target.z = curr_rot.z;
-            }
-
-            // see if we even need to do any rotation.
-            if (curr_rot != real_rot_target) {
-                // yes, we need to move back to the preferred rotation for at least one axis.
-                llSetStatus(STATUS_PHYSICS, FALSE);  // physics property gets fixed in next block.
-                llSetRot(llEuler2Rot(real_rot_target));
-            }
-        }
-
-        if (KEEP_IT_PHYSICAL) {
-            // remind the object that it's physical, or set it if it wasn't.  sometimes
-            // a physical object can get jinxed when bouncing into other people's lands
-            // and lose its status as a physical object.  we correct for that here.
-            llSetStatus(STATUS_PHYSICS, TRUE);
-        }
-
-        integer time_to_panic = FALSE;  // set to true if we should panic now.
-
-        // check whether the object is still in the appropriate region.
-        integer region_okay = (home_region == llGetRegionCorner());
-
-        // check to see if we're watching for a specific time.
-        if (last_alerted != 0) {
-            // ooh, we've already hit panicky conditions in the past.  let's see if
-            // it's time to tell the owner about it.
-            if (panic_interval() <= llAbs(llGetUnixTime() - last_alerted)) {
-                // time to tell them about this, oh yes.
-                time_to_panic = TRUE;
-            }
-        } else {
-            // evaluate whether we are in the right condition (right sim and
-            // without being boxed in).
-            if (!region_okay || (homeward_jump_attempts > MAXIMUM_FAILED_JUMPS)) {
-                // this is not a good situation.  we will now set the last alerted
-                // timer so as to force a panic message next time through the timer
-                // loop.
-                last_alerted = llAbs(llGetUnixTime() - (integer)panic_interval() - 1000);
-                // decide when to fire the timer next.
-                if (AUTO_TERMINATE) {
-                    llSetTimerEvent(0.1);  // fire very soon to zap.
-                } else {
-                    llSetTimerEvent(POSITION_CHECKING_INTERVAL * 5);
-                        // slow the checking down a bit, since we don't expect to
-                        // magically get back to our sim (although it could happen!).
-                }
-            }
-        }
-
-        // time to panic just means that we should tell the owner about our problematic
-        // location, or auto-terminate if configured that way.
-        if (time_to_panic) {
-            // well, we've got to say something about this dire situation.
-            string reason = "trapped by unfriendly turf";
-            if (!region_okay) reason = "crossed region boundary";
-            if (AUTO_TERMINATE) {
-                // enforce the rules; we left the building and we have no ticket back.
-                if (DEBUGGING) {
-                    llOwnerSay(reason + " -- object death -- was in "
-                        + llGetRegionName() + " at " + (string)llGetPos());
-                }
-                llDie();
-            }
-            // whew, we ducked that deadly issue.  let the owner know that we
-            // don't like this place.
-            llOwnerSay(reason + "; please come get me:\nlast in "
-                + llGetRegionName() + " at " + (string)llGetPos());
-            last_alerted = llGetUnixTime();  // reset, since we just alerted.
-            return;  // don't bother trying to move anywhere.
-        }
-        
-        if (region_okay && (last_alerted != 0) ) {
-            // hmmm, did we recover our position?
-            if (homeward_jump_attempts <= MAXIMUM_FAILED_JUMPS) {
-                // we didn't expend too many jumps, so try going home again.
-                last_alerted = 0;
-                // also go back to our normal timing cycle.
-                llSetTimerEvent(POSITION_CHECKING_INTERVAL);
-            }
-        }
-        
-        if (!region_okay || (homeward_jump_attempts > MAXIMUM_FAILED_JUMPS)
-            || (last_alerted != 0) ) {
-            // we said our piece, if any.  we can't be fuddling around here.
-            return;
-        }
-
-        // we're still in the right region, so check how far we are from the starting
-        // place.  we'll try to move back if someone dragged us too far away from it.
-        float distance = llVecDist(llGetPos(), home_place);
-        if (distance > MAXIMUM_ROAMING_RANGE) {
-            // this is not good; we need to get back to our starting point.
-            attempt_to_go_home();
-            homeward_jump_attempts++;
-        } else {
-            // reset our counter, since we are close enough to home.
-            homeward_jump_attempts = 0;
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/Vote_for_me_v4.2.lsl b/huffware/huffotronic_tools_n_testers_v6.1/Vote_for_me_v4.2.lsl
new file mode 100755 (executable)
index 0000000..ab8aca1
--- /dev/null
@@ -0,0 +1,426 @@
+
+// huffware script: vote for me, by fred huffhines.
+//
+// original author: ChuChu Ricardo January 14, 2010
+// numerous mods: Fred Huffhines, March 2010  [including but not limited to refactoring
+//    existing functions and fixing payment behavior]
+// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+string LINDEN_MARK = "L$";  // the money symbol for linden dollars.
+integer MINIMUM_FREE_MEMORY = 3400;  // the least memory we can get by with.
+
+// a set of menu items we'll be displaying on the voter menu.
+string ITEM_VOTEME = "Vote for Me";
+string ITEM_STATUS = "Show Info";
+string ITEM_NOT_NOW = "Not Now";
+// items for the owner menu only.
+string ITEM_RESET = "Reset";
+string ITEM_GIVE_NOTE = "Give Note";
+string ITEM_NO_NOTE = "No Notecard";
+string ITEM_GIVE_OBJ = "Give Gift";
+string ITEM_NO_OBJ = "No Gift";
+
+integer ONE_MINUTE;  // number of seconds in a minute.  initialized later.
+integer ONE_HOUR;  // number of seconds in an hour.  initialized later.
+integer FULL_DAY;  // number of seconds in a day.  initialized later.
+
+// these are the textures we'll show when it's time to register the average vote.
+list TEXTURE_UUIDS = [
+    "8dfc709a-c37d-6103-2670-d287e871f0e7",  // zero average.
+    "14278369-1db4-4497-13ef-5dc75a1017f0",  // lowest rating (red, many bars).
+    "8a891c33-1070-6c6b-148b-919651323b5e",
+    "25f8618d-181d-9af3-720e-01a3a0fa1861",
+    "3f89b392-b70a-8a63-f09f-b51f6d91b437",
+    "a6d02c4e-7b8c-0fd9-47a5-08cb61159bfa",
+    "b7fb64db-5658-547d-560d-3ca86ff77e37",
+    "bc8057e8-61f2-1919-74f9-59ea5b731bc7",
+    "ec54863f-665c-9dc0-ab64-051fe96750af",
+    "2acaa661-db7a-1035-d4e4-0ed50304887c",
+    "53f1465d-7f39-d1cc-6ade-4610ec053646",
+    "c868135f-0ad1-20ea-a85b-0c48a780ea7f",
+    "78215a59-c52b-1886-0cae-bce11592e9b1",
+    "ffa2ed36-df97-4889-4903-06dca758336d",
+    "f1a625cb-4346-91b2-8e48-9290be22ec90",
+    "6301df4e-d3bf-2b41-9738-a6e4b7f10715",
+    "a3f566fa-0e2e-68dc-92ac-a60258717525",
+    "83088c7a-8397-404d-1285-54def3ff179e",
+    "cde91186-7365-02c1-fe79-740cc82bc01a",
+    "08d22575-0848-b7c4-1dfb-665216165831"  // highest rating (green, no bars)
+];
+
+// the secret channel where the user can change the text shown on title.
+integer COMMAND_CHANNEL = 9;
+
+// global variables...
+
+key last_owner;  // the last person who owned this object.
+string persistent_message;  // additional text for the title bar.
+integer voter_dialog_channel;  // where the voter (non-owner) menu will be heard.
+integer owner_dialog_channel;  // where the owner's big menu will be heard.
+integer vote_price = 10;  // amount of lindens paid per vote, with default value.
+integer give_notecards = TRUE;  // should we hand out notecards for a vote?
+integer give_objects = TRUE;  // should we hand out objects for a vote?
+
+// these four variables need to reset daily...
+list voter_ids;  // the identities of the voters.
+list vote_magnitudes;  // the value (on the likes-me scale) of each vote cast.
+float average_score;  // Average score computed so far.
+integer last_reset_time;  // the last time we did a vote reset.
+
+// perform initialization tasks.
+setup_voteme()
+{
+    // initialize our "constants" here, since LSL doesn't like generated constants.
+    ONE_MINUTE = 60;
+    ONE_HOUR = 60 * ONE_MINUTE;
+    FULL_DAY = 24 * ONE_HOUR;
+
+    last_owner = llGetOwner();  // remember so we can know when changing hands.
+    last_reset_time = llGetUnixTime();  // track when we cranked up.
+
+    // default add-in for titler is the avatar's name.
+    persistent_message = llKey2Name(llGetOwner());
+
+    llSetText("VoteME: "+ persistent_message, <1,1,1>, 1.0);
+
+    set_faces_to_texture((key)llList2String(TEXTURE_UUIDS, 0));
+
+    llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
+
+    // set up the menu dialog channel so we will hear what they picked.
+    owner_dialog_channel = -(integer)(llFrand(999999) + 250);
+    voter_dialog_channel = owner_dialog_channel + 1;
+    llListen(owner_dialog_channel, "", llGetOwner(), "");
+    llListen(voter_dialog_channel, "", NULL_KEY, "");
+
+    // listen on our special command channel.
+    llListen(COMMAND_CHANNEL, "", llGetOwner(), "");
+
+    llSetTimerEvent(ONE_MINUTE);
+}
+
+// looks for the voter to see if they've already voted today.
+// true is returned if the "id" is found.
+integer seek_voter(key id) { return llListFindList(voter_ids, [id]) >= 0; }
+
+// adds a record for the voter with key "id", if they are not already present.
+// true is returned if this is a new voter.
+integer add_voter(key id)
+{
+    if (llGetFreeMemory() < MINIMUM_FREE_MEMORY) {
+        llOwnerSay("omitting vote due to low memory.");
+        return FALSE;
+    }
+    // if the entry's not there already, add it.
+    if (seek_voter(id)) return FALSE;  // that one was there.
+    // if we got to here, then the voter was not there yet.
+    voter_ids += [ id ];
+    return TRUE;
+}
+
+// creates a string out of the time in "decode_time" which is expected to
+// be compatible with llGetWallClock() values.
+string time_string(integer decode_time)
+{
+    integer hours = decode_time / ONE_HOUR;
+    decode_time -= hours * ONE_HOUR;
+    integer minutes = decode_time / ONE_MINUTE;
+    decode_time -= minutes * ONE_MINUTE;
+    integer seconds = decode_time;
+    return (string)hours + ":" + (string)minutes + ":" + (string)seconds;
+}
+
+// sets all the x/y faces of the object to the texture key specified.
+// the top and bottom are unchanged.
+set_faces_to_texture(key texture_id)
+{
+    integer i;
+    for (i = 1; i <= 4; i++) {
+        llSetTexture(texture_id, i);
+    }
+}
+
+// pops up the menu for the owner's use.
+show_owner_menu()
+{
+    string msg0 = "You can choose the amount you want voters to pay,\nor configure giving out notecards and/or gifts to your voters.";
+    list menu0_btns = [
+        // first row at bottom.
+        ITEM_GIVE_NOTE, ITEM_NO_NOTE, ITEM_STATUS,
+        ITEM_GIVE_OBJ, ITEM_NO_OBJ, ITEM_RESET,
+        LINDEN_MARK + "10", LINDEN_MARK + "20", LINDEN_MARK + "50",
+        // last row at top.
+        LINDEN_MARK + "100"
+    ];
+
+    llDialog(llGetOwner(), msg0, menu0_btns, owner_dialog_channel);
+}
+
+// lets the avatar know we can't process their vote right now.
+apologize_but_refuse_vote()
+{
+    llSay(0, "Sorry, You have already voted for " + llKey2Name(llGetOwner()) + " today."); 
+}
+
+key last_toucher;  // the last person that clicked the voter object.
+//move this!
+
+// handles a particular avatar that has touched the voter.
+process_toucher(integer which)
+{
+    string voter_id = llDetectedKey(which);
+    string voter_name = llDetectedName(which);
+    // see if this was the owner touching the object.
+    if (voter_id == llGetOwner()) {
+        show_owner_menu();
+        return;  // done with owner touch handling.
+    }
+    // handle when someone other than the owner touches the voter.    
+    if (!seek_voter(voter_id)) {
+        // new voter.
+        if (last_toucher != voter_id) {
+            llSay(0, "Hello " + voter_name + "... please Vote for Me.");
+            last_toucher = voter_id;
+            if (give_notecards == TRUE) {
+                string card_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
+                if (card_name != "") llGiveInventory(voter_id, card_name);
+            }
+        }
+        string msg1 = "Please Choose to Vote for me.\nYou can also choose to see my current voting status.";
+        list menu1_btns = [ ITEM_VOTEME, ITEM_STATUS, ITEM_NOT_NOW ];
+        llDialog(voter_id, msg1, menu1_btns, voter_dialog_channel);
+    } else {
+        // they had already voted, so we don't give them the whole menu.
+        string msg1 = "Thanks for your vote!  You can check my status, but you cannot vote again until tomorrow.";
+        list menu1_btns = [ ITEM_STATUS ];
+        llDialog(voter_id, msg1, menu1_btns, voter_dialog_channel);
+    }
+}
+
+// processes when an avatar touches the voter.
+handle_touches(integer total_number)
+{
+    // run through all the people that touched the voter this time.
+    integer i;
+    for (i = 0; i < total_number; i++) { process_toucher(i); }
+}
+
+// deals with people throwing money at us.
+handle_monetary_gift(key giver, integer amount)
+{
+    if (giver == llGetOwner()) {
+        // fine, genius, you gave yourself some money.  you don't get to vote.
+        return;
+    }
+    if (amount != vote_price) {
+        // refund the amount paid, since this was not the right vote cost.
+        llSay(0, "Oops!  That's not the right amount for the vote; SL is hosing up or something.  Here's a refund.");
+        llGiveMoney(giver, amount);
+        return;
+    }
+    if (seek_voter(giver)) {
+        // they've already voted so they're not allowed again.
+        apologize_but_refuse_vote();
+        llGiveMoney(giver, amount);
+        return;
+    }
+    add_voter(giver);
+    
+    llSay(0, "Thanks for the " + LINDEN_MARK + (string)amount + ", " + llKey2Name(giver)
+        + ".  Your voting menu will open shortly.");
+
+    string msg3 = "Voting Key:\n1-means you like me a little\n10-means you really adore me\nThank You!";
+    list menu3_btns = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ];
+    llDialog(giver, msg3, menu3_btns, voter_dialog_channel);
+}
+
+// announces how the owner is doing so far.
+show_status()
+{
+    integer count = llGetListLength(voter_ids);
+    llSay(0, "My name is " + llKey2Name(llGetOwner()) + " and I have received "
+        + (string)count + " votes.\n"
+        + "My average score per vote is " + (string)average_score + ".");
+
+integer since_reset = llGetUnixTime() - last_reset_time;
+llOwnerSay("last reset " + time_string(since_reset) + " H:M:S ago.");
+
+}
+
+// processes responses from menus and deals with spoken commands.
+hear_voices(integer channel, string speaker_name, key id, string message)
+{
+    // see if this is from the owner about what to show on the voter.
+    if ( (channel == COMMAND_CHANNEL) && (id == llGetOwner()) ) {
+//hmmm: undocumented!
+        persistent_message = message;
+        llOwnerSay("Changed title bar to add \"" + persistent_message + "\".");
+        llSetText("VoteME: " + persistent_message, <1,1,1>, 1.0);
+        return;
+    }
+
+    // check if the message comes from the owner's dialog.
+    if (channel == owner_dialog_channel) {
+        if (message == ITEM_STATUS) {
+            show_status();
+            return;
+        } else if (message == ITEM_RESET) {
+//hmmm: is this in the menu???
+            llOwnerSay("Resetting now...");
+            llResetScript();
+        } else if (llGetSubString(message, 0, 1) == LINDEN_MARK) {
+            vote_price = (integer)llGetSubString(message,2,-1);
+            llOwnerSay("Voting for you will now cost avatars "
+                + LINDEN_MARK + (string)vote_price + ".");
+            llSetPayPrice(PAY_HIDE, [vote_price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
+        } else if (message == ITEM_GIVE_OBJ) {
+            llOwnerSay("Gift giving enabled.");
+            give_objects = TRUE;
+        } else if (message == ITEM_NO_OBJ) {
+            llOwnerSay("Gift giving disabled.");
+            give_objects = FALSE;
+        } else if (message == ITEM_GIVE_NOTE) {
+            llOwnerSay("Notecard giving enabled.");
+            give_notecards = TRUE;
+        } else if (message == ITEM_NO_NOTE) {
+            llOwnerSay("Notecard giving disabled.");
+            give_notecards = FALSE;
+        }
+        // assume for the choices that fall through that they want to see the menu again.
+        show_owner_menu();
+        return;  // done handling our own dialog.
+    }
+
+    // see if this is the dialog for the voting person.
+    if (channel == voter_dialog_channel) {
+        if (message == ITEM_VOTEME) {
+            string msg2 = "To show your confidence in me, pay me "
+                + LINDEN_MARK + (string)vote_price + ".\n"
+                + "Then rate me from 1 to 10 after you pay.\n"
+                + "1 = You like me a little bit\n10 = You really adore me\n"
+                + "Ready?  Right-click this object and pick \"Pay\".  Thanks very much!";
+            list menu2_btns = [ "Understood" ];
+            llDialog(id, msg2, menu2_btns, voter_dialog_channel);
+        } else if (message == ITEM_STATUS) {
+            show_status();
+        } else if (message == ITEM_NOT_NOW) {
+            llSay(0, "Thanks for the interest anyhow, " + llKey2Name(id) + ".");
+        } else if ((integer)message > 0 && (integer)message <= 10) {
+            if (give_notecards == TRUE) {
+                string name = llGetInventoryName(INVENTORY_NOTECARD, 0); 
+                if (name != "") llGiveInventory(id, name);
+            }
+            if (give_objects == TRUE) {
+               string name = llGetInventoryName(INVENTORY_OBJECT, 0); 
+               if (name != "") llGiveInventory(id, name);
+            }
+            register_vote((integer)message);
+        }
+    }
+}
+
+// deals with our timer clicks.
+handle_timer()
+{
+    integer wall_clock = (integer)llGetWallclock();
+
+//llOwnerSay("tick: " +  time_string(wall_clock));
+
+    // see if it seems like time to reset.  we'll do this when the clock has just passed
+    // midnight (that is, we're in the first hour after midnight), or if the device had
+    // possibly been taken out of commission a long time ago (meaning more time has passed
+    // since the last reset than has elapsed today so far).
+    integer reset_it = FALSE;
+    integer time_since_reset = llGetUnixTime() - last_reset_time;
+    // is it the first hour of midnight, and we didn't just reset?
+    if ( (wall_clock < ONE_HOUR) && (time_since_reset > ONE_HOUR) ) reset_it = TRUE;
+    // or, is it a really long time since we did reset?  longer than when the hour turned?
+    if (time_since_reset > wall_clock) reset_it = TRUE;
+
+    if (reset_it) {
+        // aha, we've decided it's that time.
+        llOwnerSay("Resetting voters and average, since the clock rolled over.");
+        voter_ids = [];
+        vote_magnitudes = [];
+        average_score = 0;
+        last_reset_time = llGetUnixTime();
+        register_vote(0);  // just recalculate average and show texture.
+    }
+}
+
+// tracks that they've made a vote.
+register_vote(integer this_vote_value)
+{
+    // zero is a special value that just makes us recalculate the average.
+    if (this_vote_value != 0) vote_magnitudes += [ this_vote_value ];
+
+//move this to an averager method.
+    integer sum = 0;
+    integer n = llGetListLength(vote_magnitudes);
+    integer i = 0;
+    for(i = 0;i<n;i++) {
+        sum = sum + (integer)llList2String(vote_magnitudes,i);
+    }
+    if (n != 0) average_score = (float)sum/(float)n;
+    else average_score = 0;
+        
+    // Score on scale of 0 to 19
+    float new_score = average_score * 2;
+    integer tex_num = (integer)new_score;  //Ean's Texture Number
+
+    if (tex_num >= 20) tex_num = 19;  //We dont have all green texture
+        
+    set_faces_to_texture((key)llList2String(TEXTURE_UUIDS, tex_num));
+}
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+// main state machine.
+state real_default
+{
+    state_entry() { setup_voteme(); }
+
+    on_rez(integer parm) {
+        if (last_owner != llGetOwner()) {
+            llOwnerSay("Now configuring for " + llKey2Name(llGetOwner()));
+            llResetScript();
+        }
+    }
+    
+    run_time_permissions(integer perm) {
+        if (perm & PERMISSION_DEBIT) {
+//llOwnerSay("got permission for debits, will set price to " + (string)vote_price);
+            llSetPayPrice(PAY_HIDE, [vote_price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
+        } else {
+            llOwnerSay("We were denied debit permission and cannot function without it.  Use the menu and select \"" + ITEM_RESET + "\" to fix this.");
+        }
+    }
+
+    timer() { handle_timer(); }
+
+    touch_start(integer total_number) { handle_touches(total_number); }
+
+    money(key giver, integer amount) { handle_monetary_gift(giver, amount); }
+
+    listen(integer channel, string name, key id, string message)
+    { hear_voices(channel, name, id, message); }
+}
+
+
+//feature ideas:
+// have the voter track the highest paying guy?
+//   actually no, the owner sets that limit.  rats.
+//   but what about the highest voting guy!?  the guy/gal who thought the most could be tracked.
+
+//hmmm: need a helper notecard function for owner!
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/Vote_for_me_v4.2.txt b/huffware/huffotronic_tools_n_testers_v6.1/Vote_for_me_v4.2.txt
deleted file mode 100755 (executable)
index ab8aca1..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-
-// huffware script: vote for me, by fred huffhines.
-//
-// original author: ChuChu Ricardo January 14, 2010
-// numerous mods: Fred Huffhines, March 2010  [including but not limited to refactoring
-//    existing functions and fixing payment behavior]
-// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-string LINDEN_MARK = "L$";  // the money symbol for linden dollars.
-integer MINIMUM_FREE_MEMORY = 3400;  // the least memory we can get by with.
-
-// a set of menu items we'll be displaying on the voter menu.
-string ITEM_VOTEME = "Vote for Me";
-string ITEM_STATUS = "Show Info";
-string ITEM_NOT_NOW = "Not Now";
-// items for the owner menu only.
-string ITEM_RESET = "Reset";
-string ITEM_GIVE_NOTE = "Give Note";
-string ITEM_NO_NOTE = "No Notecard";
-string ITEM_GIVE_OBJ = "Give Gift";
-string ITEM_NO_OBJ = "No Gift";
-
-integer ONE_MINUTE;  // number of seconds in a minute.  initialized later.
-integer ONE_HOUR;  // number of seconds in an hour.  initialized later.
-integer FULL_DAY;  // number of seconds in a day.  initialized later.
-
-// these are the textures we'll show when it's time to register the average vote.
-list TEXTURE_UUIDS = [
-    "8dfc709a-c37d-6103-2670-d287e871f0e7",  // zero average.
-    "14278369-1db4-4497-13ef-5dc75a1017f0",  // lowest rating (red, many bars).
-    "8a891c33-1070-6c6b-148b-919651323b5e",
-    "25f8618d-181d-9af3-720e-01a3a0fa1861",
-    "3f89b392-b70a-8a63-f09f-b51f6d91b437",
-    "a6d02c4e-7b8c-0fd9-47a5-08cb61159bfa",
-    "b7fb64db-5658-547d-560d-3ca86ff77e37",
-    "bc8057e8-61f2-1919-74f9-59ea5b731bc7",
-    "ec54863f-665c-9dc0-ab64-051fe96750af",
-    "2acaa661-db7a-1035-d4e4-0ed50304887c",
-    "53f1465d-7f39-d1cc-6ade-4610ec053646",
-    "c868135f-0ad1-20ea-a85b-0c48a780ea7f",
-    "78215a59-c52b-1886-0cae-bce11592e9b1",
-    "ffa2ed36-df97-4889-4903-06dca758336d",
-    "f1a625cb-4346-91b2-8e48-9290be22ec90",
-    "6301df4e-d3bf-2b41-9738-a6e4b7f10715",
-    "a3f566fa-0e2e-68dc-92ac-a60258717525",
-    "83088c7a-8397-404d-1285-54def3ff179e",
-    "cde91186-7365-02c1-fe79-740cc82bc01a",
-    "08d22575-0848-b7c4-1dfb-665216165831"  // highest rating (green, no bars)
-];
-
-// the secret channel where the user can change the text shown on title.
-integer COMMAND_CHANNEL = 9;
-
-// global variables...
-
-key last_owner;  // the last person who owned this object.
-string persistent_message;  // additional text for the title bar.
-integer voter_dialog_channel;  // where the voter (non-owner) menu will be heard.
-integer owner_dialog_channel;  // where the owner's big menu will be heard.
-integer vote_price = 10;  // amount of lindens paid per vote, with default value.
-integer give_notecards = TRUE;  // should we hand out notecards for a vote?
-integer give_objects = TRUE;  // should we hand out objects for a vote?
-
-// these four variables need to reset daily...
-list voter_ids;  // the identities of the voters.
-list vote_magnitudes;  // the value (on the likes-me scale) of each vote cast.
-float average_score;  // Average score computed so far.
-integer last_reset_time;  // the last time we did a vote reset.
-
-// perform initialization tasks.
-setup_voteme()
-{
-    // initialize our "constants" here, since LSL doesn't like generated constants.
-    ONE_MINUTE = 60;
-    ONE_HOUR = 60 * ONE_MINUTE;
-    FULL_DAY = 24 * ONE_HOUR;
-
-    last_owner = llGetOwner();  // remember so we can know when changing hands.
-    last_reset_time = llGetUnixTime();  // track when we cranked up.
-
-    // default add-in for titler is the avatar's name.
-    persistent_message = llKey2Name(llGetOwner());
-
-    llSetText("VoteME: "+ persistent_message, <1,1,1>, 1.0);
-
-    set_faces_to_texture((key)llList2String(TEXTURE_UUIDS, 0));
-
-    llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
-
-    // set up the menu dialog channel so we will hear what they picked.
-    owner_dialog_channel = -(integer)(llFrand(999999) + 250);
-    voter_dialog_channel = owner_dialog_channel + 1;
-    llListen(owner_dialog_channel, "", llGetOwner(), "");
-    llListen(voter_dialog_channel, "", NULL_KEY, "");
-
-    // listen on our special command channel.
-    llListen(COMMAND_CHANNEL, "", llGetOwner(), "");
-
-    llSetTimerEvent(ONE_MINUTE);
-}
-
-// looks for the voter to see if they've already voted today.
-// true is returned if the "id" is found.
-integer seek_voter(key id) { return llListFindList(voter_ids, [id]) >= 0; }
-
-// adds a record for the voter with key "id", if they are not already present.
-// true is returned if this is a new voter.
-integer add_voter(key id)
-{
-    if (llGetFreeMemory() < MINIMUM_FREE_MEMORY) {
-        llOwnerSay("omitting vote due to low memory.");
-        return FALSE;
-    }
-    // if the entry's not there already, add it.
-    if (seek_voter(id)) return FALSE;  // that one was there.
-    // if we got to here, then the voter was not there yet.
-    voter_ids += [ id ];
-    return TRUE;
-}
-
-// creates a string out of the time in "decode_time" which is expected to
-// be compatible with llGetWallClock() values.
-string time_string(integer decode_time)
-{
-    integer hours = decode_time / ONE_HOUR;
-    decode_time -= hours * ONE_HOUR;
-    integer minutes = decode_time / ONE_MINUTE;
-    decode_time -= minutes * ONE_MINUTE;
-    integer seconds = decode_time;
-    return (string)hours + ":" + (string)minutes + ":" + (string)seconds;
-}
-
-// sets all the x/y faces of the object to the texture key specified.
-// the top and bottom are unchanged.
-set_faces_to_texture(key texture_id)
-{
-    integer i;
-    for (i = 1; i <= 4; i++) {
-        llSetTexture(texture_id, i);
-    }
-}
-
-// pops up the menu for the owner's use.
-show_owner_menu()
-{
-    string msg0 = "You can choose the amount you want voters to pay,\nor configure giving out notecards and/or gifts to your voters.";
-    list menu0_btns = [
-        // first row at bottom.
-        ITEM_GIVE_NOTE, ITEM_NO_NOTE, ITEM_STATUS,
-        ITEM_GIVE_OBJ, ITEM_NO_OBJ, ITEM_RESET,
-        LINDEN_MARK + "10", LINDEN_MARK + "20", LINDEN_MARK + "50",
-        // last row at top.
-        LINDEN_MARK + "100"
-    ];
-
-    llDialog(llGetOwner(), msg0, menu0_btns, owner_dialog_channel);
-}
-
-// lets the avatar know we can't process their vote right now.
-apologize_but_refuse_vote()
-{
-    llSay(0, "Sorry, You have already voted for " + llKey2Name(llGetOwner()) + " today."); 
-}
-
-key last_toucher;  // the last person that clicked the voter object.
-//move this!
-
-// handles a particular avatar that has touched the voter.
-process_toucher(integer which)
-{
-    string voter_id = llDetectedKey(which);
-    string voter_name = llDetectedName(which);
-    // see if this was the owner touching the object.
-    if (voter_id == llGetOwner()) {
-        show_owner_menu();
-        return;  // done with owner touch handling.
-    }
-    // handle when someone other than the owner touches the voter.    
-    if (!seek_voter(voter_id)) {
-        // new voter.
-        if (last_toucher != voter_id) {
-            llSay(0, "Hello " + voter_name + "... please Vote for Me.");
-            last_toucher = voter_id;
-            if (give_notecards == TRUE) {
-                string card_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
-                if (card_name != "") llGiveInventory(voter_id, card_name);
-            }
-        }
-        string msg1 = "Please Choose to Vote for me.\nYou can also choose to see my current voting status.";
-        list menu1_btns = [ ITEM_VOTEME, ITEM_STATUS, ITEM_NOT_NOW ];
-        llDialog(voter_id, msg1, menu1_btns, voter_dialog_channel);
-    } else {
-        // they had already voted, so we don't give them the whole menu.
-        string msg1 = "Thanks for your vote!  You can check my status, but you cannot vote again until tomorrow.";
-        list menu1_btns = [ ITEM_STATUS ];
-        llDialog(voter_id, msg1, menu1_btns, voter_dialog_channel);
-    }
-}
-
-// processes when an avatar touches the voter.
-handle_touches(integer total_number)
-{
-    // run through all the people that touched the voter this time.
-    integer i;
-    for (i = 0; i < total_number; i++) { process_toucher(i); }
-}
-
-// deals with people throwing money at us.
-handle_monetary_gift(key giver, integer amount)
-{
-    if (giver == llGetOwner()) {
-        // fine, genius, you gave yourself some money.  you don't get to vote.
-        return;
-    }
-    if (amount != vote_price) {
-        // refund the amount paid, since this was not the right vote cost.
-        llSay(0, "Oops!  That's not the right amount for the vote; SL is hosing up or something.  Here's a refund.");
-        llGiveMoney(giver, amount);
-        return;
-    }
-    if (seek_voter(giver)) {
-        // they've already voted so they're not allowed again.
-        apologize_but_refuse_vote();
-        llGiveMoney(giver, amount);
-        return;
-    }
-    add_voter(giver);
-    
-    llSay(0, "Thanks for the " + LINDEN_MARK + (string)amount + ", " + llKey2Name(giver)
-        + ".  Your voting menu will open shortly.");
-
-    string msg3 = "Voting Key:\n1-means you like me a little\n10-means you really adore me\nThank You!";
-    list menu3_btns = [ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" ];
-    llDialog(giver, msg3, menu3_btns, voter_dialog_channel);
-}
-
-// announces how the owner is doing so far.
-show_status()
-{
-    integer count = llGetListLength(voter_ids);
-    llSay(0, "My name is " + llKey2Name(llGetOwner()) + " and I have received "
-        + (string)count + " votes.\n"
-        + "My average score per vote is " + (string)average_score + ".");
-
-integer since_reset = llGetUnixTime() - last_reset_time;
-llOwnerSay("last reset " + time_string(since_reset) + " H:M:S ago.");
-
-}
-
-// processes responses from menus and deals with spoken commands.
-hear_voices(integer channel, string speaker_name, key id, string message)
-{
-    // see if this is from the owner about what to show on the voter.
-    if ( (channel == COMMAND_CHANNEL) && (id == llGetOwner()) ) {
-//hmmm: undocumented!
-        persistent_message = message;
-        llOwnerSay("Changed title bar to add \"" + persistent_message + "\".");
-        llSetText("VoteME: " + persistent_message, <1,1,1>, 1.0);
-        return;
-    }
-
-    // check if the message comes from the owner's dialog.
-    if (channel == owner_dialog_channel) {
-        if (message == ITEM_STATUS) {
-            show_status();
-            return;
-        } else if (message == ITEM_RESET) {
-//hmmm: is this in the menu???
-            llOwnerSay("Resetting now...");
-            llResetScript();
-        } else if (llGetSubString(message, 0, 1) == LINDEN_MARK) {
-            vote_price = (integer)llGetSubString(message,2,-1);
-            llOwnerSay("Voting for you will now cost avatars "
-                + LINDEN_MARK + (string)vote_price + ".");
-            llSetPayPrice(PAY_HIDE, [vote_price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
-        } else if (message == ITEM_GIVE_OBJ) {
-            llOwnerSay("Gift giving enabled.");
-            give_objects = TRUE;
-        } else if (message == ITEM_NO_OBJ) {
-            llOwnerSay("Gift giving disabled.");
-            give_objects = FALSE;
-        } else if (message == ITEM_GIVE_NOTE) {
-            llOwnerSay("Notecard giving enabled.");
-            give_notecards = TRUE;
-        } else if (message == ITEM_NO_NOTE) {
-            llOwnerSay("Notecard giving disabled.");
-            give_notecards = FALSE;
-        }
-        // assume for the choices that fall through that they want to see the menu again.
-        show_owner_menu();
-        return;  // done handling our own dialog.
-    }
-
-    // see if this is the dialog for the voting person.
-    if (channel == voter_dialog_channel) {
-        if (message == ITEM_VOTEME) {
-            string msg2 = "To show your confidence in me, pay me "
-                + LINDEN_MARK + (string)vote_price + ".\n"
-                + "Then rate me from 1 to 10 after you pay.\n"
-                + "1 = You like me a little bit\n10 = You really adore me\n"
-                + "Ready?  Right-click this object and pick \"Pay\".  Thanks very much!";
-            list menu2_btns = [ "Understood" ];
-            llDialog(id, msg2, menu2_btns, voter_dialog_channel);
-        } else if (message == ITEM_STATUS) {
-            show_status();
-        } else if (message == ITEM_NOT_NOW) {
-            llSay(0, "Thanks for the interest anyhow, " + llKey2Name(id) + ".");
-        } else if ((integer)message > 0 && (integer)message <= 10) {
-            if (give_notecards == TRUE) {
-                string name = llGetInventoryName(INVENTORY_NOTECARD, 0); 
-                if (name != "") llGiveInventory(id, name);
-            }
-            if (give_objects == TRUE) {
-               string name = llGetInventoryName(INVENTORY_OBJECT, 0); 
-               if (name != "") llGiveInventory(id, name);
-            }
-            register_vote((integer)message);
-        }
-    }
-}
-
-// deals with our timer clicks.
-handle_timer()
-{
-    integer wall_clock = (integer)llGetWallclock();
-
-//llOwnerSay("tick: " +  time_string(wall_clock));
-
-    // see if it seems like time to reset.  we'll do this when the clock has just passed
-    // midnight (that is, we're in the first hour after midnight), or if the device had
-    // possibly been taken out of commission a long time ago (meaning more time has passed
-    // since the last reset than has elapsed today so far).
-    integer reset_it = FALSE;
-    integer time_since_reset = llGetUnixTime() - last_reset_time;
-    // is it the first hour of midnight, and we didn't just reset?
-    if ( (wall_clock < ONE_HOUR) && (time_since_reset > ONE_HOUR) ) reset_it = TRUE;
-    // or, is it a really long time since we did reset?  longer than when the hour turned?
-    if (time_since_reset > wall_clock) reset_it = TRUE;
-
-    if (reset_it) {
-        // aha, we've decided it's that time.
-        llOwnerSay("Resetting voters and average, since the clock rolled over.");
-        voter_ids = [];
-        vote_magnitudes = [];
-        average_score = 0;
-        last_reset_time = llGetUnixTime();
-        register_vote(0);  // just recalculate average and show texture.
-    }
-}
-
-// tracks that they've made a vote.
-register_vote(integer this_vote_value)
-{
-    // zero is a special value that just makes us recalculate the average.
-    if (this_vote_value != 0) vote_magnitudes += [ this_vote_value ];
-
-//move this to an averager method.
-    integer sum = 0;
-    integer n = llGetListLength(vote_magnitudes);
-    integer i = 0;
-    for(i = 0;i<n;i++) {
-        sum = sum + (integer)llList2String(vote_magnitudes,i);
-    }
-    if (n != 0) average_score = (float)sum/(float)n;
-    else average_score = 0;
-        
-    // Score on scale of 0 to 19
-    float new_score = average_score * 2;
-    integer tex_num = (integer)new_score;  //Ean's Texture Number
-
-    if (tex_num >= 20) tex_num = 19;  //We dont have all green texture
-        
-    set_faces_to_texture((key)llList2String(TEXTURE_UUIDS, tex_num));
-}
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-// main state machine.
-state real_default
-{
-    state_entry() { setup_voteme(); }
-
-    on_rez(integer parm) {
-        if (last_owner != llGetOwner()) {
-            llOwnerSay("Now configuring for " + llKey2Name(llGetOwner()));
-            llResetScript();
-        }
-    }
-    
-    run_time_permissions(integer perm) {
-        if (perm & PERMISSION_DEBIT) {
-//llOwnerSay("got permission for debits, will set price to " + (string)vote_price);
-            llSetPayPrice(PAY_HIDE, [vote_price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
-        } else {
-            llOwnerSay("We were denied debit permission and cannot function without it.  Use the menu and select \"" + ITEM_RESET + "\" to fix this.");
-        }
-    }
-
-    timer() { handle_timer(); }
-
-    touch_start(integer total_number) { handle_touches(total_number); }
-
-    money(key giver, integer amount) { handle_monetary_gift(giver, amount); }
-
-    listen(integer channel, string name, key id, string message)
-    { hear_voices(channel, name, id, message); }
-}
-
-
-//feature ideas:
-// have the voter track the highest paying guy?
-//   actually no, the owner sets that limit.  rats.
-//   but what about the highest voting guy!?  the guy/gal who thought the most could be tracked.
-
-//hmmm: need a helper notecard function for owner!
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/a_huffotronic_update_server_v23.2.lsl b/huffware/huffotronic_tools_n_testers_v6.1/a_huffotronic_update_server_v23.2.lsl
new file mode 100755 (executable)
index 0000000..ef201cf
--- /dev/null
@@ -0,0 +1,940 @@
+
+// huffware script: huff-update server, by fred huffhines.
+//
+// this script is the server side of the update process.  it should reside in an object that
+// has all the newest versions of scripts and objects that will be updated.  when rezzed, and
+// at periodic intervals, it announces on a private chat channel that updates are available.
+// when objects respond that they might like an update, it tells them the scripts that it has
+// stored inside of it.  if any of those scripts are an older version inside the client
+// (update requesting) object, then the client will request the newer versions.  the server
+// object will stuff them into it and tell them to start running.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer IS_OPENSIM = TRUE;  // must be set to true for opensim, false for second life.
+
+integer DEBUGGING = FALSE;  // set this to true for noisier diagnostics.
+
+
+
+// updater dependency section:
+// should be moved to a notecard!!!
+//
+// format is a list of strings, where each string has a pair wrapped by the
+// huffware item separators.  the pair contains (1) the basename of a script
+// that has a new dependency and (2) the basename of that new dependency.
+list known_script_dependencies;
+
+
+
+
+load_script_deps()
+{
+    known_script_dependencies = [
+        llDumpList2String(["jaunt wik rez", "jaunt config funcs"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["jaunt wik rez", "data cow"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["jaunt wik rez", "jaunt rezolator"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["remotely personable", "inventory exchanger"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "exchange driver hudimation"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "avatar timer manager"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "avatar choice memory"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["giftorse", "particle projector"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["huff-search brainiac", "searchbert armature"], ITEM_LIST_SEPARATOR),
+
+        
+//special purpose -- removes the updater from the elevator buttons...
+//llDumpList2String(["comfortable sitting", "zap updater from elevators"], ITEM_LIST_SEPARATOR),
+// => do not uncomment unless you want your elevators to shed their ability to update.
+
+
+        // this allows us to add or remove items above at will without complaints about comma.
+        llDumpList2String(["xyzzy", "hopefully-never-matches"], ITEM_LIST_SEPARATOR)
+    ];
+}
+
+
+
+
+// global constants...
+
+integer USER_COMMAND_CHANNEL = 4;  // channel where we listen to user commands.
+
+float ANNOUNCEMENT_PERIOD = 14.0;  // how often we tell other objects that we have tasty treats.
+
+integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
+integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
+
+string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
+string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
+string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
+string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
+string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
+string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
+string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
+string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
+string DONE_UPDATING                = "#finito#";  // the client is done updating.
+string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
+
+integer UPDATER_SCRIPT_PIN          = -1231008;  // the hook for our scripts to be modified.
+
+string RESTART_UPDATER_COMMAND      = "#restart";  // said in open chat to recrank the updater.
+string SHOW_SCRIPTS_COMMAND         = "#show";  // said in open chat to list out the scripts.
+string SHUTDOWN_COMMAND             = "#destroy";  // shuts down object and destroys it.
+
+string UPDATER_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+
+string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
+
+integer ENTRIES_PER_LINE = 4;  // number of items from a list shown on one line of text.
+
+integer MAXIMUM_ACTIVE_CLIENTS = 5;  // number of conversations we will allow at a time.
+
+float LONGEST_SLACK_PER_CLIENT = 84.0;
+    // we allow a client to be out of touch with us for this many seconds.  after that,
+    // we decide it's deceased and remove it from our list.
+
+integer MESSAGE_SIZE_LIMIT = 800;  // longest thing that can be safely said without clipping (guess).
+
+float SCRIPT_LIST_PAUSE_INTERVAL = 1.4;  // pause between large chunks of update text.
+
+string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
+
+float CHANGED_INVENTORY_SNOOZER = 7.0;
+    // the number of seconds we sleep once we see an inventory change.  we don't want to
+    // react to this immediately.  this overrides the normal announcement cycle until it's
+    // dealt with by the timer.
+
+string CONTINUANCE_MARKER = "...";
+    // a string sent when the update list is too long and needs to be continued in another chat.
+
+string UPDATER_BASE_NAME = "huff-update client";
+    // the name of the updater script that keeps everything in sync.
+
+//////////////
+
+// global variables...
+
+list scripts_available;  // the list of scripts we have in our inventory for distribution.
+list objects_available;  // list of objects for handing out.
+
+list active_clients;  // list of keys for clients that are updating currently.
+list active_update_channels;  // active conversations on client chosen channels.
+list active_listen_ids;  // the ids for the listener on those channels.
+list active_timestamps;  // tracks when the client was last active.
+
+integer inventory_request_channel;  // our personal channel that the update client should talk with.
+
+integer dealing_with_change;  // has the inventory changed?  we will deal with this in the timer.
+
+// displays the status of the update server.
+show_status(key who_says)
+{
+    string title = "[mem free=" + (string)llGetFreeMemory() + "]";
+    title = "Listening for requests on channel " + (string)inventory_request_channel;
+    if (llGetListLength(active_update_channels))
+        title += "\nactive channels="
+            + dump_list(active_update_channels, FALSE, ENTRIES_PER_LINE);
+    else
+        title += "\nNo channels active.";
+        
+    if (llGetListLength(active_clients))
+        title += "\nactive clients=" + dump_keyed_list(active_clients, TRUE, 2);
+    else
+        title += "\nNo clients active.";
+    
+    if (llGetOwner() == who_says) {
+        string addition = " ";
+        if (USER_COMMAND_CHANNEL != 0) addition = "/" + (string)USER_COMMAND_CHANNEL + " ";
+        title += "\n[ \"" + addition + SHOW_SCRIPTS_COMMAND + "\" lists all the scripts, "
+            + "\"" + addition + SHUTDOWN_COMMAND + "\" zaps the updater, "
+            + "\"" + addition + RESTART_UPDATER_COMMAND + "\" refreshes the updater ]";
+    }
+
+    llWhisper(0, title);
+}
+
+// plink a quietous string of resonance...
+squonk(integer indy)
+{
+    string snd = llGetInventoryName(INVENTORY_SOUND, indy);
+    if (snd != "") llTriggerSound(snd, 1.0);
+}
+
+// list out the scripts that the server's object contains.
+show_scripts()
+{
+    string title = (string)llGetListLength(scripts_available) + " scripts available:";
+    show_list(title, scripts_available);
+    title = (string)llGetListLength(objects_available) + " objects available:";
+    show_list(title, objects_available);
+}
+
+// lets the client know that we're here and have some scripts available.
+announce_presence()
+{
+    if (llGetListLength(active_clients) < MAXIMUM_ACTIVE_CLIENTS) {
+        // only announce if we're not already booked up.
+        llWhisper(UPDATE_ANNOUNCEMENT_CHANNEL, UPDATE_ANNOUNCEMENT_PREFIX + (string)inventory_request_channel);
+    }
+}
+
+// lifted from "clear text and effects" script; should be nearly identical
+// to that, except that we set the texture animation.
+reset_all_effects()
+{
+    llSetText("", <0,0,0>, 0);  // clear any text above object.
+    llSetSitText("Sit Here");  // reset sit text to default state.
+    llSetTouchText("Touch");  // similarly for touch.
+    llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
+    llParticleSystem([]);  // turn off all particles.
+    llSensorRemove();  // stop any running sensors.
+    llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
+    llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
+    // keep it from being physical and from disapparating.
+    llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE,
+        PRIM_PHANTOM, TRUE]);
+    llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
+
+    //
+    // the following are specific to the huffotronic update server.
+    //
+
+    // we re-assert our special texture set here, in case some wayward scripts have
+    // messed with us.
+    integer textures_held = llGetInventoryNumber(INVENTORY_TEXTURE);
+    integer indy;
+    for (indy = 0; indy < textures_held; indy++) {
+        string curr_tex = llGetInventoryName(INVENTORY_TEXTURE, indy);
+        // we have a simple scheme for putting textures on the updater.
+        // we have an inside, an outside and the ends.
+        if (is_prefix(curr_tex, "~~s0")) {
+            llSetTexture(curr_tex, ALL_SIDES);
+        } else if (is_prefix(curr_tex, "~~s1")) {
+            llSetTexture(curr_tex, 1);
+        } else if (is_prefix(curr_tex, "~~s2")) {
+            llSetTexture(curr_tex, 0);
+            llSetTexture(curr_tex, 3);
+        }
+    }
+    
+    // re-assert our texture animation also.
+    llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE,
+        ALL_SIDES, 0, 0, 0, TWO_PI, 1.0 / 36.0);
+}
+
+// set up the update server object.
+initialize_root()
+{
+    // set up our particular "look".
+    reset_all_effects();
+
+    // shut down any competing scripts in this object.
+    // we try to swat any other script that's been added before we let them do weird
+    // stuff.  for example, a pet script might start acting like one.  this
+    // function is not guaranteed to run before that bad stuff can happen,
+    // and that's maybe the one major issue with this approach.  as long as
+    // the contained scripts aren't evil (like if they jump someplace else
+    // as soon as they start), then there shouldn't be any serious problems.
+    knock_down_other_scripts();
+
+    // reset our variables.
+    active_update_channels = [];
+    active_listen_ids = [];
+    active_clients = [];
+    active_timestamps = [];
+    scripts_available = [];
+    objects_available = [];
+    dealing_with_change = FALSE;  // not handling any inventory changes.
+
+    // make sure we know about any scripts that have new dependencies.
+    load_script_deps();
+
+    // clean out any older versions of the scripts before we make our
+    // inventory.
+    destroy_older_versions();
+
+    // now accumulate the list of scripts in our inventory.    
+    integer items_held = llGetInventoryNumber(INVENTORY_SCRIPT);
+    integer indy;
+    for (indy = 0; indy < items_held; indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        // we don't provide our own script for updating; it must be kept from
+        // floating around, like into other objects that are not updaters.
+////        if (curr_script != llGetScriptName())
+            scripts_available += curr_script;
+    }
+    items_held = llGetInventoryNumber(INVENTORY_OBJECT);
+    for (indy = 0; indy < items_held; indy++) {
+        objects_available += llGetInventoryName(INVENTORY_OBJECT, indy);
+//log_it("added obj: " + llGetInventoryName(INVENTORY_OBJECT, indy));
+    }
+    items_held = llGetInventoryNumber(INVENTORY_NOTECARD);
+    for (indy = 0; indy < items_held; indy++) {
+        objects_available += llGetInventoryName(INVENTORY_NOTECARD, indy);
+//log_it("added note: " + llGetInventoryName(INVENTORY_NOTECARD, indy));
+    }
+
+    // listen to the owner.
+    llListen(USER_COMMAND_CHANNEL, "", llGetOwner(), "");
+    // listen for any requests from our loyal clients.
+    inventory_request_channel = random_channel();
+    llListen(inventory_request_channel, "", NULL_KEY, "");
+    // listen for older clients too.
+    llListen(OLD_REQUEST_INVENTORY_CHANNEL, "", NULL_KEY, "");
+
+    // set up the periodic announcements.
+    llSetTimerEvent(ANNOUNCEMENT_PERIOD);
+}
+
+handle_timer()
+{
+    if (dealing_with_change) {
+        dealing_with_change = FALSE;
+        state rerun;  // zoom back to the starting point.
+    }
+    integer indy;
+    integer timecheck = llGetUnixTime();  // use for whole loop.
+    for (indy = llGetListLength(active_timestamps) - 1; indy >= 0; indy--) {
+        integer last_time = llList2Integer(active_timestamps, indy);
+        if (llAbs(last_time - timecheck) > LONGEST_SLACK_PER_CLIENT) {
+            // we need to clear out this item.  we know we can whack the client
+            // at the same index and that will take care of this slacker.
+            key curr_key = llList2Key(active_clients, indy);
+            log_it("timed-out client: " + llKey2Name(curr_key) + " [" + (string)curr_key + "]");
+            remove_client(curr_key);
+        }
+    }
+
+    // let the objects nearby know that we are open for business by
+    // announcing the script inventory.
+    announce_presence();
+}
+
+// turns a list into a nicely formatted string.
+string dump_list(list to_show, integer initial_line_break, integer entries_per_line)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we break every Nth entry, but not if it's the first line and
+        // they said to not have the initial line break.
+        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
+            msg += "\n";
+        string cursc = llList2String(to_show, indy);
+        msg += cursc;
+        // add commas where needed.
+        if (indy < llGetListLength(to_show) - 1)
+            msg += ", ";
+    }
+    return msg;
+}
+
+// similar to dump_keyed_list, but only shows the names, each on their own line.
+string dump_names_for_keys(list to_show)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we only line break after the first entry.
+        if (indy > 0) msg += "\n";
+        string keystr = llList2String(to_show, indy);
+        msg += llKey2Name(keystr);
+    }
+    return msg;
+}
+
+// similar to dump_list
+string dump_keyed_list(list to_show, integer initial_line_break, integer entries_per_line)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we break every Nth entry, but not if it's the first line and
+        // they said to not have the initial line break.
+        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
+            msg += "\n";
+        string keystr = llList2String(to_show, indy);
+        msg += llKey2Name(keystr) + " (" + keystr + ")";
+        // add commas where needed.
+        if (indy < llGetListLength(to_show) - 1)
+            msg += ", ";
+    }
+    return msg;
+}
+
+// shows the list specified in a compact manner.
+show_list(string title, list to_show)
+{
+    string to_say = title + dump_list(to_show, TRUE, ENTRIES_PER_LINE);
+    // flush some memory.
+    title = "";
+    to_show = [];
+    integer indy;
+    // say the output in pieces to avoid over-clogging chat.
+    for (indy = 0; indy < llStringLength(to_say); indy += MESSAGE_SIZE_LIMIT) {
+        integer last_indy = indy + MESSAGE_SIZE_LIMIT - 1;
+        string addition;
+        if (last_indy < llStringLength(to_say)) addition = CONTINUANCE_MARKER;
+        llWhisper(0, llGetSubString(to_say, indy, last_indy) + addition);
+    }
+}
+
+// stops all the scripts besides this one.
+knock_down_other_scripts()
+{
+    // set all scripts but this to not be running.
+    integer indy;
+    string self_script = llGetScriptName();
+    list split = compute_basename_and_version(self_script);
+    string self_base = llList2String(split, 0);
+    self_script = ""; split = [];  // free memory.
+    integer count = llGetInventoryNumber(INVENTORY_SCRIPT);
+    // we set all other scripts that are not versions of this script to not be running.
+    for (indy = 0; indy < count; indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if (!is_prefix(curr_script, self_base)
+            && !is_prefix(curr_script, UPDATER_BASE_NAME) ) {
+            llSetScriptState(curr_script, FALSE);
+        }
+    }
+}
+
+// set a text label on the updater with the list of clients.
+set_our_label()
+{
+    string label = "";
+    if (llGetListLength(active_clients) > 0) label = "[updating]\n";
+    llSetText(label + dump_names_for_keys(active_clients), <0.8, 0.95, 0.92>, 1.0);
+}
+
+// clean out a client that we should be done with.
+remove_client(key id)
+{
+    // locate said client of deceased nature...
+    integer indy = find_in_list(active_clients, id);
+    if (indy < 0) {
+//        if (DEBUGGING) log_it("failure to find client to remove: " + (string)id);
+        return;
+    }
+    active_clients = llDeleteSubList(active_clients, indy, indy);
+    // also clean out the channel and stop listening to it.
+integer act_chan = llList2Integer(active_update_channels, indy);
+    active_update_channels = llDeleteSubList(active_update_channels, indy, indy);
+    integer listen_to_remove = llList2Integer(active_listen_ids, indy);
+//log_it("remove listen " + (string)listen_to_remove + " on chan " + (string)act_chan);
+    llListenRemove(listen_to_remove);
+    active_listen_ids = llDeleteSubList(active_listen_ids, indy, indy);
+    active_timestamps = llDeleteSubList(active_timestamps, indy, indy);
+    set_our_label();
+}
+
+// fix a partial match to a script name if we can't find the exact item.
+string backpatch_script_name(string partial)
+{
+    if (llGetInventoryType(partial) == INVENTORY_SCRIPT) return partial;  // all set.
+    integer dep_indy;
+    for (dep_indy = 0; dep_indy < llGetInventoryNumber(INVENTORY_SCRIPT); dep_indy++) {
+        string curr_name = llGetInventoryName(INVENTORY_SCRIPT, dep_indy);
+        if (is_prefix(curr_name, partial)) {
+//            log_it("found real name " + curr_name + " for part: " + partial);
+            return curr_name;
+        }
+    }
+//    log_it("no matches for partial script name!");
+    return "";  // no matches!
+}
+
+// moves the upgrade process with "id" along to the next step given the request in
+// the message.
+propel_upgrade_process(integer channel, key id, string message)
+{
+    if (DEBUGGING) log_it("got upgrade note from " + (string)id + " with msg=" + message);
+    if (message == REQUEST_SCRIPT_UPDATE) {
+        // begins the update process with the client.
+        llSay(channel, SHUT_THEM_DOWN);
+    } else if (is_prefix(message, READY_TO_UPDATE)) {
+        // whack the prefix so we can get the list they want.
+        message = llDeleteSubString(message, 0, llStringLength(READY_TO_UPDATE) - 1);
+        list requests = llParseString2List(message, [UPDATER_PARM_SEPARATOR], []);
+        message = "";
+        // send over the scripts the client asked for, since it seems to be ready for them.
+        if (llGetListLength(requests)) {
+            show_list("updating " + llKey2Name(id) + " (key " + (string)id + ") with", requests);
+            integer indy;
+            for (indy = 0; indy < llGetListLength(requests); indy++) {
+                string curr = llList2String(requests, indy);
+                if (find_in_list(objects_available, curr) >= 0) {
+//log_it("handing object over: " + curr);
+                    // it's an object, so treat it that way.
+                    llGiveInventory(id, curr);
+                } else {
+//log_it("handing script over: " + curr);
+                    // assume it's a script, and use script pin to stuff it.
+                    curr = backpatch_script_name(curr);
+                    if (curr != "") {
+//                        integer starting_state = FALSE;
+// second life was okay with scripts being plugged in unstarted.  opensim is not.
+// and second life appears to be unhappy with scripts plugged in as started.  so we
+// have an impasse.
+// this should be: true for opensim, and false for second life.
+                        integer starting_state = IS_OPENSIM;
+//                        if (DEBUGGING) log_it("installing script using updater pin.");
+                        llRemoteLoadScriptPin(id, curr, UPDATER_SCRIPT_PIN, starting_state, 0);
+                    }
+                }
+            }
+        }
+    } else if (message == SCRIPTS_ARE_CURRENT) {
+        // the client thinks it's ready to get back up and running.
+//log_it("heard client is ready!");
+        llSay(channel, START_THEM_UP);
+        // kludge for older clients (pre 10.4 version) to try to help them start up.
+//old and not useful.        llSleep(0.2); llSay(channel, START_THEM_UP); llSleep(0.2); llSay(channel, START_THEM_UP);
+        remove_client(id);
+    } else if (message == DONE_UPDATING) {
+        // this client has nothing to do for now.
+//log_it("heard client is done: " + (string)id);
+        remove_client(id);
+    } else {
+//log_it("weird note from client: " + message);
+        return;  // not used.
+    }
+    
+}
+
+// blasts out the inventory list to a curious client.
+spew_inventory_list(integer channel, string message, key id)
+{
+    if (!is_prefix(message, REQUEST_INVENTORY_PREFIX)) {
+
+        // this is an old style update alert that we still use at startup of the client
+        // to ensure that finishing replacement of the updater script is never unnoticed.
+        if (is_prefix(message, DONE_UPDATING)) {
+//            if (DEBUGGING) log_it("found very special message from startup of updater.");
+            propel_upgrade_process(channel, id, message);
+        }
+        
+        // argh, this is not the right kind of message on our channel.
+        return;
+    }
+    string chan_str = llDeleteSubString(message, 0, llStringLength(REQUEST_INVENTORY_PREFIX) - 1);
+    integer new_update_channel = (integer)chan_str;    
+    if (llGetListLength(active_clients) >= MAXIMUM_ACTIVE_CLIENTS) {
+        // got to tell them "not right now".  we'll pretend we have no
+        // scripts; they'll know what we mean if the update client is
+        // recent enough.  really old clients will just go to sleep until later.
+        if (DEBUGGING) log_it("having to disallow new client '" + llKey2Name(id) + "', too many now.");
+        llSay(new_update_channel, REPORT_AVAILABLE_SCRIPTS + BUSY_BUSY);
+        return;
+    }
+
+    // looks like we're going to try to handle the request for them.    
+    if (DEBUGGING) log_it("server heard update req on chan " + (string)channel + " from: " + llKey2Name(id));
+    
+//log_it("add client convo chan " + (string)new_update_channel);
+    integer existing_indy = find_in_list(active_clients, id);
+    if (existing_indy < 0) {
+        active_clients += id;
+        active_update_channels += new_update_channel;
+        integer new_listen_id = llListen(new_update_channel, "", id, "");
+//log_it("add listen " + (string)new_listen_id + " on chan " + (string)new_update_channel);
+        active_listen_ids += new_listen_id;
+        active_timestamps += llGetUnixTime();
+        set_our_label();
+    } else {
+//        if (DEBUGGING) log_it("same client came back before finishing previous upgrade, rolling with it.");
+        // delete old listener so we don't leave it dangling.
+        integer old_listen_id = llList2Integer(active_listen_ids, existing_indy);
+//log_it("remove old listen " + (string)old_listen_id);
+        llListenRemove(old_listen_id);
+        // update the channel and listener id for the new registration.
+        active_update_channels = chop_list(active_update_channels, 0, existing_indy - 1)
+            + [ new_update_channel ]
+            + chop_list(active_update_channels, existing_indy + 1,
+                llGetListLength(active_update_channels) - 1);
+        integer new_listen_id = llListen(new_update_channel, "", id, "");
+//log_it("add new listen " + (string)new_listen_id);
+        active_listen_ids = chop_list(active_listen_ids, 0, existing_indy - 1)
+            + [ new_listen_id ]
+            + chop_list(active_listen_ids, existing_indy + 1,
+                llGetListLength(active_listen_ids) - 1);
+        active_timestamps = chop_list(active_timestamps, 0, existing_indy - 1)
+            + [ new_listen_id ]
+            + chop_list(active_timestamps, existing_indy + 1,
+                llGetListLength(active_timestamps) - 1);
+    }
+
+    // our report name is always called available scripts, but it can actually have
+    // script dependency definitions, script names and object names.
+    string msg = REPORT_AVAILABLE_SCRIPTS;
+    string curr;  // temp.
+
+    // add in the huff updater, since that's the most crucial that they know we have.
+    integer posn;
+    string UPDATE_CLIENT_SCRIPT = "huff-update client";
+    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
+        curr = llList2String(scripts_available, posn);
+        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
+                == UPDATE_CLIENT_SCRIPT) {
+//log_it("found "  + curr);
+            msg += curr + UPDATER_PARM_SEPARATOR;
+            posn = 99999;  // jump out.
+        }
+        if (DEBUGGING && (posn == llGetListLength(scripts_available) - 1) ) {
+            log_it("epic fail, found no updater client script.");
+        }
+    }
+
+    // speak about the dependencies that we know.
+    for (posn = 0; posn < llGetListLength(known_script_dependencies); posn++) {
+        msg += SCRIPT_DEPENDENCY_MARK
+            + llList2String(known_script_dependencies, posn) + UPDATER_PARM_SEPARATOR;
+        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+            msg = REPORT_AVAILABLE_SCRIPTS;
+        }
+    }        
+    // tell this new client what scripts we have.
+    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
+        curr = llList2String(scripts_available, posn);
+        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
+                != UPDATE_CLIENT_SCRIPT) {            
+            // add in the next item, along with the parameter separator.
+            msg += curr + UPDATER_PARM_SEPARATOR;
+//log_it("adding " + curr);
+            if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+                llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+                if (channel == OLD_REQUEST_INVENTORY_CHANNEL) {
+                    // stop sending the list to them since they may not know how
+                    // to interpret a multiple part update list.
+                    return;
+                }
+                llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+                msg = REPORT_AVAILABLE_SCRIPTS;
+            }
+        }
+    }
+    // mention any objects that are available.
+    for (posn = 0; posn < llGetListLength(objects_available); posn++) {
+        // add in the next item, along with the parameter separator.            
+        msg += llList2String(objects_available, posn)
+            + UPDATER_PARM_SEPARATOR;
+        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+            msg = REPORT_AVAILABLE_SCRIPTS;
+        }
+    }
+    // say final bit, even if it's mostly blank.  we need to let them know
+    // that we're done and not adding that continuation flag string.
+    llSay(new_update_channel, msg);
+}
+
+// handles verbal commands from objects that want updates.
+process_verbal_requests(integer channel, string name, key id, string message)
+{
+    if ( (channel == OLD_REQUEST_INVENTORY_CHANNEL) || (channel == inventory_request_channel) ) {
+        spew_inventory_list(channel, message, id);
+        return;
+    } else if (channel == USER_COMMAND_CHANNEL) {
+if (DEBUGGING) log_it("heard orders: " + message);
+        // simple verbal commands.
+        if (message == RESTART_UPDATER_COMMAND) {
+            log_it("Restarting now.");
+            llResetScript();
+        } else if (message == SHOW_SCRIPTS_COMMAND) {
+            show_scripts();
+        } else if (message == SHUTDOWN_COMMAND) {
+            // we will de-rez now (i.e., die) if we are not one of the special names that is undying.
+            if (!matches_substring(llGetObjectName(), "keeper")) {
+//                log_it("server " + (string)inventory_request_channel + " now disintegrating.");
+                squonk(1);
+                llDie();
+            }
+        }
+        return;
+    }
+
+    integer indy;
+    // see if the channel is for one of our valid updates that's in progress.
+    for (indy = 0; indy < llGetListLength(active_update_channels); indy++) {
+        integer cur_chan = llList2Integer(active_update_channels, indy);
+        if (cur_chan == channel) {
+            // yes, this is really for that guy.
+            propel_upgrade_process(channel, id, message);
+            return;
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+//    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// a random channel for the first interaction with the client.
+integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+    
+    if (IS_OPENSIM && (llGetListLength(removal_list) > 0) ) {
+        log_it("now restarting to avoid opensim late updating change event.");
+        llResetScript();
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+    // thirdly, try to clean out the notecards.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.4.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+default
+{
+    state_entry()
+    {
+        auto_retire();
+        initialize_root();  // get set up to start answering requests.
+        llWhisper(0, llGetScriptName() + " started...  touch for more info.");
+        squonk(0);
+    }
+    
+    state_exit() { llSetTimerEvent(0); }
+
+    on_rez(integer parm) {
+        state rerun;
+    }
+
+    timer() { handle_timer(); }
+
+    touch_start(integer count) {
+        show_status(llDetectedKey(0));
+    }
+    
+    listen(integer channel, string name, key id, string message) {
+        // make sure that the object is something we should even talk to.
+        if (llGetOwnerKey(id) != llGetOwner()) {
+            return;
+        }
+        // looks okay, let's see if this is useful communication.
+        process_verbal_requests(channel, name, id, message); 
+    }
+
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            log_it("inventory changed, scheduled a restart.");
+            // sleep a little bit; otherwise we get SL noise about scripts not being
+            // there when it told us they were there.  this can lead to some scripts
+            // doing bizarre things if they are running when added.
+            dealing_with_change = TRUE;
+            llSetTimerEvent(0.0);  // kludge to get around second life bug.
+            llSetTimerEvent(CHANGED_INVENTORY_SNOOZER);
+        }
+    }
+}
+
+state rerun { state_entry() { state default; } }
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/a_huffotronic_update_server_v23.2.txt b/huffware/huffotronic_tools_n_testers_v6.1/a_huffotronic_update_server_v23.2.txt
deleted file mode 100755 (executable)
index ef201cf..0000000
+++ /dev/null
@@ -1,940 +0,0 @@
-
-// huffware script: huff-update server, by fred huffhines.
-//
-// this script is the server side of the update process.  it should reside in an object that
-// has all the newest versions of scripts and objects that will be updated.  when rezzed, and
-// at periodic intervals, it announces on a private chat channel that updates are available.
-// when objects respond that they might like an update, it tells them the scripts that it has
-// stored inside of it.  if any of those scripts are an older version inside the client
-// (update requesting) object, then the client will request the newer versions.  the server
-// object will stuff them into it and tell them to start running.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer IS_OPENSIM = TRUE;  // must be set to true for opensim, false for second life.
-
-integer DEBUGGING = FALSE;  // set this to true for noisier diagnostics.
-
-
-
-// updater dependency section:
-// should be moved to a notecard!!!
-//
-// format is a list of strings, where each string has a pair wrapped by the
-// huffware item separators.  the pair contains (1) the basename of a script
-// that has a new dependency and (2) the basename of that new dependency.
-list known_script_dependencies;
-
-
-
-
-load_script_deps()
-{
-    known_script_dependencies = [
-        llDumpList2String(["jaunt wik rez", "jaunt config funcs"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["jaunt wik rez", "data cow"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["jaunt wik rez", "jaunt rezolator"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["remotely personable", "inventory exchanger"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "exchange driver hudimation"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "avatar timer manager"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "avatar choice memory"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["giftorse", "particle projector"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["huff-search brainiac", "searchbert armature"], ITEM_LIST_SEPARATOR),
-
-        
-//special purpose -- removes the updater from the elevator buttons...
-//llDumpList2String(["comfortable sitting", "zap updater from elevators"], ITEM_LIST_SEPARATOR),
-// => do not uncomment unless you want your elevators to shed their ability to update.
-
-
-        // this allows us to add or remove items above at will without complaints about comma.
-        llDumpList2String(["xyzzy", "hopefully-never-matches"], ITEM_LIST_SEPARATOR)
-    ];
-}
-
-
-
-
-// global constants...
-
-integer USER_COMMAND_CHANNEL = 4;  // channel where we listen to user commands.
-
-float ANNOUNCEMENT_PERIOD = 14.0;  // how often we tell other objects that we have tasty treats.
-
-integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
-integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
-
-string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
-string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
-string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
-string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
-string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
-string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
-string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
-string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
-string DONE_UPDATING                = "#finito#";  // the client is done updating.
-string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
-
-integer UPDATER_SCRIPT_PIN          = -1231008;  // the hook for our scripts to be modified.
-
-string RESTART_UPDATER_COMMAND      = "#restart";  // said in open chat to recrank the updater.
-string SHOW_SCRIPTS_COMMAND         = "#show";  // said in open chat to list out the scripts.
-string SHUTDOWN_COMMAND             = "#destroy";  // shuts down object and destroys it.
-
-string UPDATER_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-
-string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
-
-integer ENTRIES_PER_LINE = 4;  // number of items from a list shown on one line of text.
-
-integer MAXIMUM_ACTIVE_CLIENTS = 5;  // number of conversations we will allow at a time.
-
-float LONGEST_SLACK_PER_CLIENT = 84.0;
-    // we allow a client to be out of touch with us for this many seconds.  after that,
-    // we decide it's deceased and remove it from our list.
-
-integer MESSAGE_SIZE_LIMIT = 800;  // longest thing that can be safely said without clipping (guess).
-
-float SCRIPT_LIST_PAUSE_INTERVAL = 1.4;  // pause between large chunks of update text.
-
-string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
-
-float CHANGED_INVENTORY_SNOOZER = 7.0;
-    // the number of seconds we sleep once we see an inventory change.  we don't want to
-    // react to this immediately.  this overrides the normal announcement cycle until it's
-    // dealt with by the timer.
-
-string CONTINUANCE_MARKER = "...";
-    // a string sent when the update list is too long and needs to be continued in another chat.
-
-string UPDATER_BASE_NAME = "huff-update client";
-    // the name of the updater script that keeps everything in sync.
-
-//////////////
-
-// global variables...
-
-list scripts_available;  // the list of scripts we have in our inventory for distribution.
-list objects_available;  // list of objects for handing out.
-
-list active_clients;  // list of keys for clients that are updating currently.
-list active_update_channels;  // active conversations on client chosen channels.
-list active_listen_ids;  // the ids for the listener on those channels.
-list active_timestamps;  // tracks when the client was last active.
-
-integer inventory_request_channel;  // our personal channel that the update client should talk with.
-
-integer dealing_with_change;  // has the inventory changed?  we will deal with this in the timer.
-
-// displays the status of the update server.
-show_status(key who_says)
-{
-    string title = "[mem free=" + (string)llGetFreeMemory() + "]";
-    title = "Listening for requests on channel " + (string)inventory_request_channel;
-    if (llGetListLength(active_update_channels))
-        title += "\nactive channels="
-            + dump_list(active_update_channels, FALSE, ENTRIES_PER_LINE);
-    else
-        title += "\nNo channels active.";
-        
-    if (llGetListLength(active_clients))
-        title += "\nactive clients=" + dump_keyed_list(active_clients, TRUE, 2);
-    else
-        title += "\nNo clients active.";
-    
-    if (llGetOwner() == who_says) {
-        string addition = " ";
-        if (USER_COMMAND_CHANNEL != 0) addition = "/" + (string)USER_COMMAND_CHANNEL + " ";
-        title += "\n[ \"" + addition + SHOW_SCRIPTS_COMMAND + "\" lists all the scripts, "
-            + "\"" + addition + SHUTDOWN_COMMAND + "\" zaps the updater, "
-            + "\"" + addition + RESTART_UPDATER_COMMAND + "\" refreshes the updater ]";
-    }
-
-    llWhisper(0, title);
-}
-
-// plink a quietous string of resonance...
-squonk(integer indy)
-{
-    string snd = llGetInventoryName(INVENTORY_SOUND, indy);
-    if (snd != "") llTriggerSound(snd, 1.0);
-}
-
-// list out the scripts that the server's object contains.
-show_scripts()
-{
-    string title = (string)llGetListLength(scripts_available) + " scripts available:";
-    show_list(title, scripts_available);
-    title = (string)llGetListLength(objects_available) + " objects available:";
-    show_list(title, objects_available);
-}
-
-// lets the client know that we're here and have some scripts available.
-announce_presence()
-{
-    if (llGetListLength(active_clients) < MAXIMUM_ACTIVE_CLIENTS) {
-        // only announce if we're not already booked up.
-        llWhisper(UPDATE_ANNOUNCEMENT_CHANNEL, UPDATE_ANNOUNCEMENT_PREFIX + (string)inventory_request_channel);
-    }
-}
-
-// lifted from "clear text and effects" script; should be nearly identical
-// to that, except that we set the texture animation.
-reset_all_effects()
-{
-    llSetText("", <0,0,0>, 0);  // clear any text above object.
-    llSetSitText("Sit Here");  // reset sit text to default state.
-    llSetTouchText("Touch");  // similarly for touch.
-    llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
-    llParticleSystem([]);  // turn off all particles.
-    llSensorRemove();  // stop any running sensors.
-    llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
-    llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
-    // keep it from being physical and from disapparating.
-    llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE,
-        PRIM_PHANTOM, TRUE]);
-    llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
-
-    //
-    // the following are specific to the huffotronic update server.
-    //
-
-    // we re-assert our special texture set here, in case some wayward scripts have
-    // messed with us.
-    integer textures_held = llGetInventoryNumber(INVENTORY_TEXTURE);
-    integer indy;
-    for (indy = 0; indy < textures_held; indy++) {
-        string curr_tex = llGetInventoryName(INVENTORY_TEXTURE, indy);
-        // we have a simple scheme for putting textures on the updater.
-        // we have an inside, an outside and the ends.
-        if (is_prefix(curr_tex, "~~s0")) {
-            llSetTexture(curr_tex, ALL_SIDES);
-        } else if (is_prefix(curr_tex, "~~s1")) {
-            llSetTexture(curr_tex, 1);
-        } else if (is_prefix(curr_tex, "~~s2")) {
-            llSetTexture(curr_tex, 0);
-            llSetTexture(curr_tex, 3);
-        }
-    }
-    
-    // re-assert our texture animation also.
-    llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE,
-        ALL_SIDES, 0, 0, 0, TWO_PI, 1.0 / 36.0);
-}
-
-// set up the update server object.
-initialize_root()
-{
-    // set up our particular "look".
-    reset_all_effects();
-
-    // shut down any competing scripts in this object.
-    // we try to swat any other script that's been added before we let them do weird
-    // stuff.  for example, a pet script might start acting like one.  this
-    // function is not guaranteed to run before that bad stuff can happen,
-    // and that's maybe the one major issue with this approach.  as long as
-    // the contained scripts aren't evil (like if they jump someplace else
-    // as soon as they start), then there shouldn't be any serious problems.
-    knock_down_other_scripts();
-
-    // reset our variables.
-    active_update_channels = [];
-    active_listen_ids = [];
-    active_clients = [];
-    active_timestamps = [];
-    scripts_available = [];
-    objects_available = [];
-    dealing_with_change = FALSE;  // not handling any inventory changes.
-
-    // make sure we know about any scripts that have new dependencies.
-    load_script_deps();
-
-    // clean out any older versions of the scripts before we make our
-    // inventory.
-    destroy_older_versions();
-
-    // now accumulate the list of scripts in our inventory.    
-    integer items_held = llGetInventoryNumber(INVENTORY_SCRIPT);
-    integer indy;
-    for (indy = 0; indy < items_held; indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        // we don't provide our own script for updating; it must be kept from
-        // floating around, like into other objects that are not updaters.
-////        if (curr_script != llGetScriptName())
-            scripts_available += curr_script;
-    }
-    items_held = llGetInventoryNumber(INVENTORY_OBJECT);
-    for (indy = 0; indy < items_held; indy++) {
-        objects_available += llGetInventoryName(INVENTORY_OBJECT, indy);
-//log_it("added obj: " + llGetInventoryName(INVENTORY_OBJECT, indy));
-    }
-    items_held = llGetInventoryNumber(INVENTORY_NOTECARD);
-    for (indy = 0; indy < items_held; indy++) {
-        objects_available += llGetInventoryName(INVENTORY_NOTECARD, indy);
-//log_it("added note: " + llGetInventoryName(INVENTORY_NOTECARD, indy));
-    }
-
-    // listen to the owner.
-    llListen(USER_COMMAND_CHANNEL, "", llGetOwner(), "");
-    // listen for any requests from our loyal clients.
-    inventory_request_channel = random_channel();
-    llListen(inventory_request_channel, "", NULL_KEY, "");
-    // listen for older clients too.
-    llListen(OLD_REQUEST_INVENTORY_CHANNEL, "", NULL_KEY, "");
-
-    // set up the periodic announcements.
-    llSetTimerEvent(ANNOUNCEMENT_PERIOD);
-}
-
-handle_timer()
-{
-    if (dealing_with_change) {
-        dealing_with_change = FALSE;
-        state rerun;  // zoom back to the starting point.
-    }
-    integer indy;
-    integer timecheck = llGetUnixTime();  // use for whole loop.
-    for (indy = llGetListLength(active_timestamps) - 1; indy >= 0; indy--) {
-        integer last_time = llList2Integer(active_timestamps, indy);
-        if (llAbs(last_time - timecheck) > LONGEST_SLACK_PER_CLIENT) {
-            // we need to clear out this item.  we know we can whack the client
-            // at the same index and that will take care of this slacker.
-            key curr_key = llList2Key(active_clients, indy);
-            log_it("timed-out client: " + llKey2Name(curr_key) + " [" + (string)curr_key + "]");
-            remove_client(curr_key);
-        }
-    }
-
-    // let the objects nearby know that we are open for business by
-    // announcing the script inventory.
-    announce_presence();
-}
-
-// turns a list into a nicely formatted string.
-string dump_list(list to_show, integer initial_line_break, integer entries_per_line)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we break every Nth entry, but not if it's the first line and
-        // they said to not have the initial line break.
-        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
-            msg += "\n";
-        string cursc = llList2String(to_show, indy);
-        msg += cursc;
-        // add commas where needed.
-        if (indy < llGetListLength(to_show) - 1)
-            msg += ", ";
-    }
-    return msg;
-}
-
-// similar to dump_keyed_list, but only shows the names, each on their own line.
-string dump_names_for_keys(list to_show)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we only line break after the first entry.
-        if (indy > 0) msg += "\n";
-        string keystr = llList2String(to_show, indy);
-        msg += llKey2Name(keystr);
-    }
-    return msg;
-}
-
-// similar to dump_list
-string dump_keyed_list(list to_show, integer initial_line_break, integer entries_per_line)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we break every Nth entry, but not if it's the first line and
-        // they said to not have the initial line break.
-        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
-            msg += "\n";
-        string keystr = llList2String(to_show, indy);
-        msg += llKey2Name(keystr) + " (" + keystr + ")";
-        // add commas where needed.
-        if (indy < llGetListLength(to_show) - 1)
-            msg += ", ";
-    }
-    return msg;
-}
-
-// shows the list specified in a compact manner.
-show_list(string title, list to_show)
-{
-    string to_say = title + dump_list(to_show, TRUE, ENTRIES_PER_LINE);
-    // flush some memory.
-    title = "";
-    to_show = [];
-    integer indy;
-    // say the output in pieces to avoid over-clogging chat.
-    for (indy = 0; indy < llStringLength(to_say); indy += MESSAGE_SIZE_LIMIT) {
-        integer last_indy = indy + MESSAGE_SIZE_LIMIT - 1;
-        string addition;
-        if (last_indy < llStringLength(to_say)) addition = CONTINUANCE_MARKER;
-        llWhisper(0, llGetSubString(to_say, indy, last_indy) + addition);
-    }
-}
-
-// stops all the scripts besides this one.
-knock_down_other_scripts()
-{
-    // set all scripts but this to not be running.
-    integer indy;
-    string self_script = llGetScriptName();
-    list split = compute_basename_and_version(self_script);
-    string self_base = llList2String(split, 0);
-    self_script = ""; split = [];  // free memory.
-    integer count = llGetInventoryNumber(INVENTORY_SCRIPT);
-    // we set all other scripts that are not versions of this script to not be running.
-    for (indy = 0; indy < count; indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if (!is_prefix(curr_script, self_base)
-            && !is_prefix(curr_script, UPDATER_BASE_NAME) ) {
-            llSetScriptState(curr_script, FALSE);
-        }
-    }
-}
-
-// set a text label on the updater with the list of clients.
-set_our_label()
-{
-    string label = "";
-    if (llGetListLength(active_clients) > 0) label = "[updating]\n";
-    llSetText(label + dump_names_for_keys(active_clients), <0.8, 0.95, 0.92>, 1.0);
-}
-
-// clean out a client that we should be done with.
-remove_client(key id)
-{
-    // locate said client of deceased nature...
-    integer indy = find_in_list(active_clients, id);
-    if (indy < 0) {
-//        if (DEBUGGING) log_it("failure to find client to remove: " + (string)id);
-        return;
-    }
-    active_clients = llDeleteSubList(active_clients, indy, indy);
-    // also clean out the channel and stop listening to it.
-integer act_chan = llList2Integer(active_update_channels, indy);
-    active_update_channels = llDeleteSubList(active_update_channels, indy, indy);
-    integer listen_to_remove = llList2Integer(active_listen_ids, indy);
-//log_it("remove listen " + (string)listen_to_remove + " on chan " + (string)act_chan);
-    llListenRemove(listen_to_remove);
-    active_listen_ids = llDeleteSubList(active_listen_ids, indy, indy);
-    active_timestamps = llDeleteSubList(active_timestamps, indy, indy);
-    set_our_label();
-}
-
-// fix a partial match to a script name if we can't find the exact item.
-string backpatch_script_name(string partial)
-{
-    if (llGetInventoryType(partial) == INVENTORY_SCRIPT) return partial;  // all set.
-    integer dep_indy;
-    for (dep_indy = 0; dep_indy < llGetInventoryNumber(INVENTORY_SCRIPT); dep_indy++) {
-        string curr_name = llGetInventoryName(INVENTORY_SCRIPT, dep_indy);
-        if (is_prefix(curr_name, partial)) {
-//            log_it("found real name " + curr_name + " for part: " + partial);
-            return curr_name;
-        }
-    }
-//    log_it("no matches for partial script name!");
-    return "";  // no matches!
-}
-
-// moves the upgrade process with "id" along to the next step given the request in
-// the message.
-propel_upgrade_process(integer channel, key id, string message)
-{
-    if (DEBUGGING) log_it("got upgrade note from " + (string)id + " with msg=" + message);
-    if (message == REQUEST_SCRIPT_UPDATE) {
-        // begins the update process with the client.
-        llSay(channel, SHUT_THEM_DOWN);
-    } else if (is_prefix(message, READY_TO_UPDATE)) {
-        // whack the prefix so we can get the list they want.
-        message = llDeleteSubString(message, 0, llStringLength(READY_TO_UPDATE) - 1);
-        list requests = llParseString2List(message, [UPDATER_PARM_SEPARATOR], []);
-        message = "";
-        // send over the scripts the client asked for, since it seems to be ready for them.
-        if (llGetListLength(requests)) {
-            show_list("updating " + llKey2Name(id) + " (key " + (string)id + ") with", requests);
-            integer indy;
-            for (indy = 0; indy < llGetListLength(requests); indy++) {
-                string curr = llList2String(requests, indy);
-                if (find_in_list(objects_available, curr) >= 0) {
-//log_it("handing object over: " + curr);
-                    // it's an object, so treat it that way.
-                    llGiveInventory(id, curr);
-                } else {
-//log_it("handing script over: " + curr);
-                    // assume it's a script, and use script pin to stuff it.
-                    curr = backpatch_script_name(curr);
-                    if (curr != "") {
-//                        integer starting_state = FALSE;
-// second life was okay with scripts being plugged in unstarted.  opensim is not.
-// and second life appears to be unhappy with scripts plugged in as started.  so we
-// have an impasse.
-// this should be: true for opensim, and false for second life.
-                        integer starting_state = IS_OPENSIM;
-//                        if (DEBUGGING) log_it("installing script using updater pin.");
-                        llRemoteLoadScriptPin(id, curr, UPDATER_SCRIPT_PIN, starting_state, 0);
-                    }
-                }
-            }
-        }
-    } else if (message == SCRIPTS_ARE_CURRENT) {
-        // the client thinks it's ready to get back up and running.
-//log_it("heard client is ready!");
-        llSay(channel, START_THEM_UP);
-        // kludge for older clients (pre 10.4 version) to try to help them start up.
-//old and not useful.        llSleep(0.2); llSay(channel, START_THEM_UP); llSleep(0.2); llSay(channel, START_THEM_UP);
-        remove_client(id);
-    } else if (message == DONE_UPDATING) {
-        // this client has nothing to do for now.
-//log_it("heard client is done: " + (string)id);
-        remove_client(id);
-    } else {
-//log_it("weird note from client: " + message);
-        return;  // not used.
-    }
-    
-}
-
-// blasts out the inventory list to a curious client.
-spew_inventory_list(integer channel, string message, key id)
-{
-    if (!is_prefix(message, REQUEST_INVENTORY_PREFIX)) {
-
-        // this is an old style update alert that we still use at startup of the client
-        // to ensure that finishing replacement of the updater script is never unnoticed.
-        if (is_prefix(message, DONE_UPDATING)) {
-//            if (DEBUGGING) log_it("found very special message from startup of updater.");
-            propel_upgrade_process(channel, id, message);
-        }
-        
-        // argh, this is not the right kind of message on our channel.
-        return;
-    }
-    string chan_str = llDeleteSubString(message, 0, llStringLength(REQUEST_INVENTORY_PREFIX) - 1);
-    integer new_update_channel = (integer)chan_str;    
-    if (llGetListLength(active_clients) >= MAXIMUM_ACTIVE_CLIENTS) {
-        // got to tell them "not right now".  we'll pretend we have no
-        // scripts; they'll know what we mean if the update client is
-        // recent enough.  really old clients will just go to sleep until later.
-        if (DEBUGGING) log_it("having to disallow new client '" + llKey2Name(id) + "', too many now.");
-        llSay(new_update_channel, REPORT_AVAILABLE_SCRIPTS + BUSY_BUSY);
-        return;
-    }
-
-    // looks like we're going to try to handle the request for them.    
-    if (DEBUGGING) log_it("server heard update req on chan " + (string)channel + " from: " + llKey2Name(id));
-    
-//log_it("add client convo chan " + (string)new_update_channel);
-    integer existing_indy = find_in_list(active_clients, id);
-    if (existing_indy < 0) {
-        active_clients += id;
-        active_update_channels += new_update_channel;
-        integer new_listen_id = llListen(new_update_channel, "", id, "");
-//log_it("add listen " + (string)new_listen_id + " on chan " + (string)new_update_channel);
-        active_listen_ids += new_listen_id;
-        active_timestamps += llGetUnixTime();
-        set_our_label();
-    } else {
-//        if (DEBUGGING) log_it("same client came back before finishing previous upgrade, rolling with it.");
-        // delete old listener so we don't leave it dangling.
-        integer old_listen_id = llList2Integer(active_listen_ids, existing_indy);
-//log_it("remove old listen " + (string)old_listen_id);
-        llListenRemove(old_listen_id);
-        // update the channel and listener id for the new registration.
-        active_update_channels = chop_list(active_update_channels, 0, existing_indy - 1)
-            + [ new_update_channel ]
-            + chop_list(active_update_channels, existing_indy + 1,
-                llGetListLength(active_update_channels) - 1);
-        integer new_listen_id = llListen(new_update_channel, "", id, "");
-//log_it("add new listen " + (string)new_listen_id);
-        active_listen_ids = chop_list(active_listen_ids, 0, existing_indy - 1)
-            + [ new_listen_id ]
-            + chop_list(active_listen_ids, existing_indy + 1,
-                llGetListLength(active_listen_ids) - 1);
-        active_timestamps = chop_list(active_timestamps, 0, existing_indy - 1)
-            + [ new_listen_id ]
-            + chop_list(active_timestamps, existing_indy + 1,
-                llGetListLength(active_timestamps) - 1);
-    }
-
-    // our report name is always called available scripts, but it can actually have
-    // script dependency definitions, script names and object names.
-    string msg = REPORT_AVAILABLE_SCRIPTS;
-    string curr;  // temp.
-
-    // add in the huff updater, since that's the most crucial that they know we have.
-    integer posn;
-    string UPDATE_CLIENT_SCRIPT = "huff-update client";
-    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
-        curr = llList2String(scripts_available, posn);
-        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
-                == UPDATE_CLIENT_SCRIPT) {
-//log_it("found "  + curr);
-            msg += curr + UPDATER_PARM_SEPARATOR;
-            posn = 99999;  // jump out.
-        }
-        if (DEBUGGING && (posn == llGetListLength(scripts_available) - 1) ) {
-            log_it("epic fail, found no updater client script.");
-        }
-    }
-
-    // speak about the dependencies that we know.
-    for (posn = 0; posn < llGetListLength(known_script_dependencies); posn++) {
-        msg += SCRIPT_DEPENDENCY_MARK
-            + llList2String(known_script_dependencies, posn) + UPDATER_PARM_SEPARATOR;
-        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-            msg = REPORT_AVAILABLE_SCRIPTS;
-        }
-    }        
-    // tell this new client what scripts we have.
-    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
-        curr = llList2String(scripts_available, posn);
-        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
-                != UPDATE_CLIENT_SCRIPT) {            
-            // add in the next item, along with the parameter separator.
-            msg += curr + UPDATER_PARM_SEPARATOR;
-//log_it("adding " + curr);
-            if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-                llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-                if (channel == OLD_REQUEST_INVENTORY_CHANNEL) {
-                    // stop sending the list to them since they may not know how
-                    // to interpret a multiple part update list.
-                    return;
-                }
-                llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-                msg = REPORT_AVAILABLE_SCRIPTS;
-            }
-        }
-    }
-    // mention any objects that are available.
-    for (posn = 0; posn < llGetListLength(objects_available); posn++) {
-        // add in the next item, along with the parameter separator.            
-        msg += llList2String(objects_available, posn)
-            + UPDATER_PARM_SEPARATOR;
-        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-            msg = REPORT_AVAILABLE_SCRIPTS;
-        }
-    }
-    // say final bit, even if it's mostly blank.  we need to let them know
-    // that we're done and not adding that continuation flag string.
-    llSay(new_update_channel, msg);
-}
-
-// handles verbal commands from objects that want updates.
-process_verbal_requests(integer channel, string name, key id, string message)
-{
-    if ( (channel == OLD_REQUEST_INVENTORY_CHANNEL) || (channel == inventory_request_channel) ) {
-        spew_inventory_list(channel, message, id);
-        return;
-    } else if (channel == USER_COMMAND_CHANNEL) {
-if (DEBUGGING) log_it("heard orders: " + message);
-        // simple verbal commands.
-        if (message == RESTART_UPDATER_COMMAND) {
-            log_it("Restarting now.");
-            llResetScript();
-        } else if (message == SHOW_SCRIPTS_COMMAND) {
-            show_scripts();
-        } else if (message == SHUTDOWN_COMMAND) {
-            // we will de-rez now (i.e., die) if we are not one of the special names that is undying.
-            if (!matches_substring(llGetObjectName(), "keeper")) {
-//                log_it("server " + (string)inventory_request_channel + " now disintegrating.");
-                squonk(1);
-                llDie();
-            }
-        }
-        return;
-    }
-
-    integer indy;
-    // see if the channel is for one of our valid updates that's in progress.
-    for (indy = 0; indy < llGetListLength(active_update_channels); indy++) {
-        integer cur_chan = llList2Integer(active_update_channels, indy);
-        if (cur_chan == channel) {
-            // yes, this is really for that guy.
-            propel_upgrade_process(channel, id, message);
-            return;
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-//    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// a random channel for the first interaction with the client.
-integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-    
-    if (IS_OPENSIM && (llGetListLength(removal_list) > 0) ) {
-        log_it("now restarting to avoid opensim late updating change event.");
-        llResetScript();
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-    // thirdly, try to clean out the notecards.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.4.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-default
-{
-    state_entry()
-    {
-        auto_retire();
-        initialize_root();  // get set up to start answering requests.
-        llWhisper(0, llGetScriptName() + " started...  touch for more info.");
-        squonk(0);
-    }
-    
-    state_exit() { llSetTimerEvent(0); }
-
-    on_rez(integer parm) {
-        state rerun;
-    }
-
-    timer() { handle_timer(); }
-
-    touch_start(integer count) {
-        show_status(llDetectedKey(0));
-    }
-    
-    listen(integer channel, string name, key id, string message) {
-        // make sure that the object is something we should even talk to.
-        if (llGetOwnerKey(id) != llGetOwner()) {
-            return;
-        }
-        // looks okay, let's see if this is useful communication.
-        process_verbal_requests(channel, name, id, message); 
-    }
-
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            log_it("inventory changed, scheduled a restart.");
-            // sleep a little bit; otherwise we get SL noise about scripts not being
-            // there when it told us they were there.  this can lead to some scripts
-            // doing bizarre things if they are running when added.
-            dealing_with_change = TRUE;
-            llSetTimerEvent(0.0);  // kludge to get around second life bug.
-            llSetTimerEvent(CHANGED_INVENTORY_SNOOZER);
-        }
-    }
-}
-
-state rerun { state_entry() { state default; } }
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/a_jumping_bean_v2.7.lsl b/huffware/huffotronic_tools_n_testers_v6.1/a_jumping_bean_v2.7.lsl
new file mode 100755 (executable)
index 0000000..e08b3b4
--- /dev/null
@@ -0,0 +1,186 @@
+
+// huffware script: a jumping bean, by fred huffhines
+//
+// an object will hop around randomly when it has this script.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+float MINIMUM_IMPULSE_MULTIPLIER = 0.05;
+    // the smallest amount we will allow the object to be bumped, relative to its mass.
+float Z_IMPULSE_MULTIPLIER = 3.4;
+    // we push the object upwards relative to its mass by this amount (or less, since
+    // we randomly choose a value up to this large).
+float X_IMPULSE_MULTIPLIER = 0.8;
+float Y_IMPULSE_MULTIPLIER = 0.8;
+    // there are smaller x and y components possible.
+
+float MINIMUM_ROTATION_MULTIPLIER = 0.001;
+// multipliers for rotation.
+float X_ROTATION_MULTIPLIER = 0.08;
+float Y_ROTATION_MULTIPLIER = 0.08;
+float Z_ROTATION_MULTIPLIER = 0.08;
+
+//////////////
+// from hufflets...
+//
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+//
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();  // make sure newest addition is only version of script.
+        llSetTimerEvent(0.3);
+    }
+
+    timer()
+    {
+        if (llFrand(1.0) > 0.5) {
+            vector impulsive = <randomize_within_range(MINIMUM_IMPULSE_MULTIPLIER, X_IMPULSE_MULTIPLIER, TRUE),
+                randomize_within_range(MINIMUM_IMPULSE_MULTIPLIER, Y_IMPULSE_MULTIPLIER, TRUE),
+                randomize_within_range(MINIMUM_IMPULSE_MULTIPLIER, Z_IMPULSE_MULTIPLIER, TRUE)>;
+            llApplyImpulse(llGetMass() * impulsive, FALSE);
+            impulsive = <randomize_within_range(MINIMUM_ROTATION_MULTIPLIER, X_ROTATION_MULTIPLIER, TRUE),
+                randomize_within_range(MINIMUM_ROTATION_MULTIPLIER, Y_ROTATION_MULTIPLIER, TRUE),
+                randomize_within_range(MINIMUM_ROTATION_MULTIPLIER, Z_ROTATION_MULTIPLIER, TRUE)>;
+            llApplyRotationalImpulse(impulsive, FALSE);
+        }
+    }
+
+    changed(integer change) {
+        if (change & CHANGED_LINK) {
+            key av = llAvatarOnSitTarget();
+            if (av != NULL_KEY) {
+                // someone sat down; let's animate them to make them tuck into the
+                // bean, if possible.
+                llStartAnimation("crouch");
+            }
+        }
+    }
+    
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/a_jumping_bean_v2.7.txt b/huffware/huffotronic_tools_n_testers_v6.1/a_jumping_bean_v2.7.txt
deleted file mode 100755 (executable)
index e08b3b4..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-
-// huffware script: a jumping bean, by fred huffhines
-//
-// an object will hop around randomly when it has this script.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-float MINIMUM_IMPULSE_MULTIPLIER = 0.05;
-    // the smallest amount we will allow the object to be bumped, relative to its mass.
-float Z_IMPULSE_MULTIPLIER = 3.4;
-    // we push the object upwards relative to its mass by this amount (or less, since
-    // we randomly choose a value up to this large).
-float X_IMPULSE_MULTIPLIER = 0.8;
-float Y_IMPULSE_MULTIPLIER = 0.8;
-    // there are smaller x and y components possible.
-
-float MINIMUM_ROTATION_MULTIPLIER = 0.001;
-// multipliers for rotation.
-float X_ROTATION_MULTIPLIER = 0.08;
-float Y_ROTATION_MULTIPLIER = 0.08;
-float Z_ROTATION_MULTIPLIER = 0.08;
-
-//////////////
-// from hufflets...
-//
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-//
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();  // make sure newest addition is only version of script.
-        llSetTimerEvent(0.3);
-    }
-
-    timer()
-    {
-        if (llFrand(1.0) > 0.5) {
-            vector impulsive = <randomize_within_range(MINIMUM_IMPULSE_MULTIPLIER, X_IMPULSE_MULTIPLIER, TRUE),
-                randomize_within_range(MINIMUM_IMPULSE_MULTIPLIER, Y_IMPULSE_MULTIPLIER, TRUE),
-                randomize_within_range(MINIMUM_IMPULSE_MULTIPLIER, Z_IMPULSE_MULTIPLIER, TRUE)>;
-            llApplyImpulse(llGetMass() * impulsive, FALSE);
-            impulsive = <randomize_within_range(MINIMUM_ROTATION_MULTIPLIER, X_ROTATION_MULTIPLIER, TRUE),
-                randomize_within_range(MINIMUM_ROTATION_MULTIPLIER, Y_ROTATION_MULTIPLIER, TRUE),
-                randomize_within_range(MINIMUM_ROTATION_MULTIPLIER, Z_ROTATION_MULTIPLIER, TRUE)>;
-            llApplyRotationalImpulse(impulsive, FALSE);
-        }
-    }
-
-    changed(integer change) {
-        if (change & CHANGED_LINK) {
-            key av = llAvatarOnSitTarget();
-            if (av != NULL_KEY) {
-                // someone sat down; let's animate them to make them tuck into the
-                // bean, if possible.
-                llStartAnimation("crouch");
-            }
-        }
-    }
-    
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/altitudinator_v1.1.lsl b/huffware/huffotronic_tools_n_testers_v6.1/altitudinator_v1.1.lsl
new file mode 100755 (executable)
index 0000000..74830f0
--- /dev/null
@@ -0,0 +1,156 @@
+
+// huffware script: altitudinator, by fred huffhines
+//
+// displays an altimeter reading in the object's text.
+// modified by fred huffhines, originally from LSL scripting library.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        llSetTimerEvent(.01); // How often your timer() event updates
+    }
+
+    timer()
+    {
+        vector pos = llGetPos(); // Gets your current position
+        vector size = llGetAgentSize(llGetOwner()); // Get the dimensions of your agent
+        size.z = size.z / 2.0; // Halve the height element of your agent, get altitude from feet
+        float aboveground = ((float)pos.z - llGround(<0.0,0.0,0.0>) - size.z); // Distance above ground 
+        if (aboveground < 0.0) // If it thinks your feet are below ground 
+        {
+            aboveground = llSqrt(aboveground * aboveground); // - flip it
+        }
+        if (aboveground < 0.09) // Check the margin of error for zeroing - you can redefine this
+        {
+            aboveground = 0.0; // Zero it out
+        }
+        vector Speed = llGetVel(); // LSL function that should be fixed in next release.
+        float RealSpeed = llVecMag(Speed); // Convert it to velocity you can use.
+        float abovewater = llWater(<0.0,0.0,0.0>) - pos.z; // difference between yourwater height
+        if (pos.z >= llWater(<0.0,0.0,0.0>)) // If at or above water
+        {
+            abovewater = llSqrt(abovewater * abovewater);             
+        }        
+        if (pos.z < llWater(<0.0,0.0,0.0>)) // If underwater
+        {
+            abovewater = abovewater - (abovewater * 2.0); // Push the number into the negative range      
+        }
+//        string current = llGetText();
+        llSetText("Sea Lvl ALT: " + (string)abovewater + "\n" + "Grnd Lvl ALT: "
+            + (string)(aboveground) + "\nSpeed: " + (string)RealSpeed, <0.1,0.8,0.3>, 1.0); // Emit string          
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/altitudinator_v1.1.txt b/huffware/huffotronic_tools_n_testers_v6.1/altitudinator_v1.1.txt
deleted file mode 100755 (executable)
index 74830f0..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-
-// huffware script: altitudinator, by fred huffhines
-//
-// displays an altimeter reading in the object's text.
-// modified by fred huffhines, originally from LSL scripting library.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        llSetTimerEvent(.01); // How often your timer() event updates
-    }
-
-    timer()
-    {
-        vector pos = llGetPos(); // Gets your current position
-        vector size = llGetAgentSize(llGetOwner()); // Get the dimensions of your agent
-        size.z = size.z / 2.0; // Halve the height element of your agent, get altitude from feet
-        float aboveground = ((float)pos.z - llGround(<0.0,0.0,0.0>) - size.z); // Distance above ground 
-        if (aboveground < 0.0) // If it thinks your feet are below ground 
-        {
-            aboveground = llSqrt(aboveground * aboveground); // - flip it
-        }
-        if (aboveground < 0.09) // Check the margin of error for zeroing - you can redefine this
-        {
-            aboveground = 0.0; // Zero it out
-        }
-        vector Speed = llGetVel(); // LSL function that should be fixed in next release.
-        float RealSpeed = llVecMag(Speed); // Convert it to velocity you can use.
-        float abovewater = llWater(<0.0,0.0,0.0>) - pos.z; // difference between yourwater height
-        if (pos.z >= llWater(<0.0,0.0,0.0>)) // If at or above water
-        {
-            abovewater = llSqrt(abovewater * abovewater);             
-        }        
-        if (pos.z < llWater(<0.0,0.0,0.0>)) // If underwater
-        {
-            abovewater = abovewater - (abovewater * 2.0); // Push the number into the negative range      
-        }
-//        string current = llGetText();
-        llSetText("Sea Lvl ALT: " + (string)abovewater + "\n" + "Grnd Lvl ALT: "
-            + (string)(aboveground) + "\nSpeed: " + (string)RealSpeed, <0.1,0.8,0.3>, 1.0); // Emit string          
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/ama_omega_et_al_vendor_owner-only_v0.5.lsl b/huffware/huffotronic_tools_n_testers_v6.1/ama_omega_et_al_vendor_owner-only_v0.5.lsl
new file mode 100755 (executable)
index 0000000..784fdc3
--- /dev/null
@@ -0,0 +1,261 @@
+//Multi Vendor by Adelle Fitzgerald
+//Based on the Ama Omega Vendor Script v0.3.1 06/2004
+
+//Licenced under Creative Commons Attribution-Share Alike 3.0 Unported - http://creativecommons.org/licenses/by-sa/3.0/
+
+
+//You are free:
+
+//    * to Share â€” to copy, distribute and transmit the work
+//    * to Remix â€” to adapt the work
+
+//Under the following conditions:
+
+//    * Attribution â€” You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
+
+//    * Share Alike â€” If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.
+
+//With the understanding that:
+
+//    * Waiver â€” Any of the above conditions can be waived if you get permission from the copyright holder.
+//    * Public Domain â€” Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license.
+//    * Other Rights â€” In no way are any of the following rights affected by the license:
+//          o Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
+//          o The author's moral rights;
+//          o Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
+//    * Notice â€” For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
+
+//Disclaimer
+
+//The Commons Deed is not a license. It is simply a handy reference for understanding the Legal Code (the full license) â€” it is a human-readable expression of some of its key terms. Think of it as the user-friendly interface to the Legal Code beneath. This Deed itself has no legal value, and its contents do not appear in the actual license.
+
+//Creative Commons is not a law firm and does not provide legal services. Distributing of, displaying of, or linking to this Commons Deed does not create an attorney-client relationship.
+
+
+integer gChannel;
+integer handle;
+string name = "Vendor ";
+integer display;
+list pics;
+list desc;
+list items;
+list sold;
+list info;
+key gUser;
+key k;
+list temp;
+integer line;
+integer l;
+string s;
+string hText;
+integer totItems;
+string button;
+
+
+incSold(integer i)
+{
+    sold = llListInsertList(llDeleteSubList(sold,i,i),[(integer)(llList2Integer(sold,i) + 1)],i);
+}
+
+doMenu()
+{
+    //llSay(0,(string)gChannel + " : " + (string)gUser); //say gChannel
+    llSetTimerEvent(30);
+    llDialog(gUser, "Settings:", ["Cancel", "Report", "Get Item", "Reset"], gChannel);
+}
+
+doCancel()
+{
+    llListenControl(handle, FALSE);
+    llSetTimerEvent(0);
+}
+
+next()
+{
+    display += 1;
+    if (display >= llGetListLength(items)) display = 0;
+    llSetText("Item: " + (string)(display + 1) + " of " + (string)totItems + "\n" + llList2String(items,display) + "\n" + llList2String(desc,display),<1,1,1>,1);
+    llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey((key)llList2String(pics,display)));
+    llMessageLinked(LINK_SET,1,"LOADNEXT",llGetInventoryKey((key)llList2String(pics,display + 1)));
+    llMessageLinked(LINK_SET,1,"LOADPREV",llGetInventoryKey((key)llList2String(pics,display - 1))); 
+}
+
+prev()
+{
+    display -= 1;
+    if (display < 0) display = llGetListLength(items) - 1;
+    llSetText("Item: " + (string)(display + 1) + " of " + (string)totItems + "\n" + llList2String(items,display) + "\n" + llList2String(desc,display),<1,1,1>,1);
+    llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey((key)llList2String(pics,display)));
+    llMessageLinked(LINK_SET,1,"LOADNEXT",llGetInventoryKey((key)llList2String(pics,display + 1)));
+    llMessageLinked(LINK_SET,1,"LOADPREV",llGetInventoryKey((key)llList2String(pics,display - 1)));
+}
+
+init()
+{
+    display = 0;
+    if (display < 0) display = llGetListLength(items) - 1;
+    llSetText("Item: " + (string)(display + 1) + " of " + (string)totItems + "\n" + llList2String(items,display) + "\n" + llList2String(desc,display),<1,1,1>,1);
+    llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey((key)llList2String(pics,display)));
+    llMessageLinked(LINK_SET,1,"LOADNEXT",llGetInventoryKey((key)llList2String(pics,display + 1)));
+    llMessageLinked(LINK_SET,1,"LOADPREV",llGetInventoryKey((key)llList2String(pics,display - 1)));
+}
+
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry()
+    {
+        state
+        readCard;
+    }
+}
+    
+state running
+{    
+    state_entry()
+    {
+        gChannel = (integer)llFrand(2147423647) + 10000;
+        handle = llListen(gChannel, "", llGetOwner(), "");
+        llListenControl(handle, FALSE);
+        init();
+    }
+    
+    on_rez(integer param)
+    {
+        llResetScript();
+    }
+    
+    listen(integer chan, string name, key id, string mes)
+    {
+        if (id != llGetOwner()) {
+            llWhisper(0, "Sorry, this vendor is restricted for use by its owner.");
+            return;
+        }
+        if (mes == "Reset")
+        {
+            doCancel();
+            state readCard;
+        }
+        else if (mes == "Report")
+        {
+            integer i;
+            for(i=0;i<llGetListLength(sold);i++)
+            {
+                if (llList2Integer(sold,i) != 0) llWhisper(0,"* Sold " + (string)llList2Integer(sold,i) + " " + llList2String(items,i));
+            }
+            doCancel();
+        }
+        else if (mes == "Get Item")
+        {
+            llGiveInventory(gUser, llList2String(items,display));
+            llWhisper(0,"Thank you, please enjoy your " + llList2String(items,display));
+            doCancel();
+        }
+        else if (mes == "Cancel")
+        {
+            doCancel();
+        }
+    }
+    
+    touch_start(integer num_detected)
+    {
+        button = llGetLinkName(llDetectedLinkNumber(0));
+        gUser = llDetectedKey(0);
+        
+        if (button == "Next")
+        {
+            next();
+        }
+        else if (button == "Prev")
+        {
+            prev();
+        }
+        else if (button == "Info")
+        {
+            llGiveInventory(gUser, llList2String(info,display));
+        }
+        else
+        {
+            if (gUser != llGetOwner()) {
+                llWhisper(0, "Sorry, this vendor is restricted for use by its owner.");
+                return;
+            }
+            if (gUser == llGetOwner())
+            {
+                llListenControl(handle, TRUE);
+                doMenu();
+            }
+            else
+            {
+                incSold(display);
+                llGiveInventory(gUser, llList2String(items,display));
+                llWhisper(0,"Thank you, please enjoy your " + llList2String(items,display));
+            }
+        }
+    }                   
+    timer()
+    {
+        doCancel();
+        llInstantMessage(gUser,"Menu timed out");
+    }
+}
+
+state readCard
+{
+    state_entry()
+    {
+        llSay(0,"Initializing...");
+        line = 1;
+        k = llGetNotecardLine("VendorConfig",line++);
+        items = [];
+        pics = [];
+        desc = [];
+    }
+    
+    dataserver(key q, string data)
+    {
+        if (q == k)
+        {
+            if (data == "")
+            {
+                k = llGetNotecardLine("VendorConfig",line++);
+                return;
+            }
+            temp = llCSV2List(data);
+            if (llParseString2List(data,[" "],[]) == []);
+            else if (data == EOF)
+            {
+                display = 0;
+                totItems = llGetListLength(items);
+                llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey(llList2String(pics,0)));
+                llWhisper(0," * Vendor setup complete : " + (string)totItems + " items loaded.");
+                state running;
+            }
+            else if (llGetListLength(temp) != 4)
+            {
+                llWhisper(0,"Error, improperly formatted line #" + (string)(line - 1));
+                state running;
+            }
+            else
+            {
+                items += llList2String(temp,0);
+                pics += llList2String(temp,1);
+                desc += llList2String(temp,2);
+                info += llList2String(temp,3);
+                sold += [(integer)0];
+                if ( llGetInventoryKey((key)llList2String(temp,0)) == NULL_KEY || llGetInventoryKey((key)llList2String(temp,1)) == NULL_KEY)
+                {
+                    llWhisper(0,"Error, missing inventory or picture from line : " + data);
+                    state running;
+                }
+                k = llGetNotecardLine("VendorConfig",line++);
+            }
+        }
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/ama_omega_et_al_vendor_owner-only_v0.5.txt b/huffware/huffotronic_tools_n_testers_v6.1/ama_omega_et_al_vendor_owner-only_v0.5.txt
deleted file mode 100755 (executable)
index 784fdc3..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-//Multi Vendor by Adelle Fitzgerald
-//Based on the Ama Omega Vendor Script v0.3.1 06/2004
-
-//Licenced under Creative Commons Attribution-Share Alike 3.0 Unported - http://creativecommons.org/licenses/by-sa/3.0/
-
-
-//You are free:
-
-//    * to Share â€” to copy, distribute and transmit the work
-//    * to Remix â€” to adapt the work
-
-//Under the following conditions:
-
-//    * Attribution â€” You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
-
-//    * Share Alike â€” If you alter, transform, or build upon this work, you may distribute the resulting work only under the same, similar or a compatible license.
-
-//With the understanding that:
-
-//    * Waiver â€” Any of the above conditions can be waived if you get permission from the copyright holder.
-//    * Public Domain â€” Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license.
-//    * Other Rights â€” In no way are any of the following rights affected by the license:
-//          o Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations;
-//          o The author's moral rights;
-//          o Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights.
-//    * Notice â€” For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page.
-
-//Disclaimer
-
-//The Commons Deed is not a license. It is simply a handy reference for understanding the Legal Code (the full license) â€” it is a human-readable expression of some of its key terms. Think of it as the user-friendly interface to the Legal Code beneath. This Deed itself has no legal value, and its contents do not appear in the actual license.
-
-//Creative Commons is not a law firm and does not provide legal services. Distributing of, displaying of, or linking to this Commons Deed does not create an attorney-client relationship.
-
-
-integer gChannel;
-integer handle;
-string name = "Vendor ";
-integer display;
-list pics;
-list desc;
-list items;
-list sold;
-list info;
-key gUser;
-key k;
-list temp;
-integer line;
-integer l;
-string s;
-string hText;
-integer totItems;
-string button;
-
-
-incSold(integer i)
-{
-    sold = llListInsertList(llDeleteSubList(sold,i,i),[(integer)(llList2Integer(sold,i) + 1)],i);
-}
-
-doMenu()
-{
-    //llSay(0,(string)gChannel + " : " + (string)gUser); //say gChannel
-    llSetTimerEvent(30);
-    llDialog(gUser, "Settings:", ["Cancel", "Report", "Get Item", "Reset"], gChannel);
-}
-
-doCancel()
-{
-    llListenControl(handle, FALSE);
-    llSetTimerEvent(0);
-}
-
-next()
-{
-    display += 1;
-    if (display >= llGetListLength(items)) display = 0;
-    llSetText("Item: " + (string)(display + 1) + " of " + (string)totItems + "\n" + llList2String(items,display) + "\n" + llList2String(desc,display),<1,1,1>,1);
-    llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey((key)llList2String(pics,display)));
-    llMessageLinked(LINK_SET,1,"LOADNEXT",llGetInventoryKey((key)llList2String(pics,display + 1)));
-    llMessageLinked(LINK_SET,1,"LOADPREV",llGetInventoryKey((key)llList2String(pics,display - 1))); 
-}
-
-prev()
-{
-    display -= 1;
-    if (display < 0) display = llGetListLength(items) - 1;
-    llSetText("Item: " + (string)(display + 1) + " of " + (string)totItems + "\n" + llList2String(items,display) + "\n" + llList2String(desc,display),<1,1,1>,1);
-    llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey((key)llList2String(pics,display)));
-    llMessageLinked(LINK_SET,1,"LOADNEXT",llGetInventoryKey((key)llList2String(pics,display + 1)));
-    llMessageLinked(LINK_SET,1,"LOADPREV",llGetInventoryKey((key)llList2String(pics,display - 1)));
-}
-
-init()
-{
-    display = 0;
-    if (display < 0) display = llGetListLength(items) - 1;
-    llSetText("Item: " + (string)(display + 1) + " of " + (string)totItems + "\n" + llList2String(items,display) + "\n" + llList2String(desc,display),<1,1,1>,1);
-    llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey((key)llList2String(pics,display)));
-    llMessageLinked(LINK_SET,1,"LOADNEXT",llGetInventoryKey((key)llList2String(pics,display + 1)));
-    llMessageLinked(LINK_SET,1,"LOADPREV",llGetInventoryKey((key)llList2String(pics,display - 1)));
-}
-
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry()
-    {
-        state
-        readCard;
-    }
-}
-    
-state running
-{    
-    state_entry()
-    {
-        gChannel = (integer)llFrand(2147423647) + 10000;
-        handle = llListen(gChannel, "", llGetOwner(), "");
-        llListenControl(handle, FALSE);
-        init();
-    }
-    
-    on_rez(integer param)
-    {
-        llResetScript();
-    }
-    
-    listen(integer chan, string name, key id, string mes)
-    {
-        if (id != llGetOwner()) {
-            llWhisper(0, "Sorry, this vendor is restricted for use by its owner.");
-            return;
-        }
-        if (mes == "Reset")
-        {
-            doCancel();
-            state readCard;
-        }
-        else if (mes == "Report")
-        {
-            integer i;
-            for(i=0;i<llGetListLength(sold);i++)
-            {
-                if (llList2Integer(sold,i) != 0) llWhisper(0,"* Sold " + (string)llList2Integer(sold,i) + " " + llList2String(items,i));
-            }
-            doCancel();
-        }
-        else if (mes == "Get Item")
-        {
-            llGiveInventory(gUser, llList2String(items,display));
-            llWhisper(0,"Thank you, please enjoy your " + llList2String(items,display));
-            doCancel();
-        }
-        else if (mes == "Cancel")
-        {
-            doCancel();
-        }
-    }
-    
-    touch_start(integer num_detected)
-    {
-        button = llGetLinkName(llDetectedLinkNumber(0));
-        gUser = llDetectedKey(0);
-        
-        if (button == "Next")
-        {
-            next();
-        }
-        else if (button == "Prev")
-        {
-            prev();
-        }
-        else if (button == "Info")
-        {
-            llGiveInventory(gUser, llList2String(info,display));
-        }
-        else
-        {
-            if (gUser != llGetOwner()) {
-                llWhisper(0, "Sorry, this vendor is restricted for use by its owner.");
-                return;
-            }
-            if (gUser == llGetOwner())
-            {
-                llListenControl(handle, TRUE);
-                doMenu();
-            }
-            else
-            {
-                incSold(display);
-                llGiveInventory(gUser, llList2String(items,display));
-                llWhisper(0,"Thank you, please enjoy your " + llList2String(items,display));
-            }
-        }
-    }                   
-    timer()
-    {
-        doCancel();
-        llInstantMessage(gUser,"Menu timed out");
-    }
-}
-
-state readCard
-{
-    state_entry()
-    {
-        llSay(0,"Initializing...");
-        line = 1;
-        k = llGetNotecardLine("VendorConfig",line++);
-        items = [];
-        pics = [];
-        desc = [];
-    }
-    
-    dataserver(key q, string data)
-    {
-        if (q == k)
-        {
-            if (data == "")
-            {
-                k = llGetNotecardLine("VendorConfig",line++);
-                return;
-            }
-            temp = llCSV2List(data);
-            if (llParseString2List(data,[" "],[]) == []);
-            else if (data == EOF)
-            {
-                display = 0;
-                totItems = llGetListLength(items);
-                llMessageLinked(LINK_SET,1,"PIC",llGetInventoryKey(llList2String(pics,0)));
-                llWhisper(0," * Vendor setup complete : " + (string)totItems + " items loaded.");
-                state running;
-            }
-            else if (llGetListLength(temp) != 4)
-            {
-                llWhisper(0,"Error, improperly formatted line #" + (string)(line - 1));
-                state running;
-            }
-            else
-            {
-                items += llList2String(temp,0);
-                pics += llList2String(temp,1);
-                desc += llList2String(temp,2);
-                info += llList2String(temp,3);
-                sold += [(integer)0];
-                if ( llGetInventoryKey((key)llList2String(temp,0)) == NULL_KEY || llGetInventoryKey((key)llList2String(temp,1)) == NULL_KEY)
-                {
-                    llWhisper(0,"Error, missing inventory or picture from line : " + data);
-                    state running;
-                }
-                k = llGetNotecardLine("VendorConfig",line++);
-            }
-        }
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/animated_texture_v0.4.lsl b/huffware/huffotronic_tools_n_testers_v6.1/animated_texture_v0.4.lsl
new file mode 100755 (executable)
index 0000000..6cc510b
--- /dev/null
@@ -0,0 +1,23 @@
+
+// huffware script: animated texture, by fred huffhines.
+//
+// super simple texture animation, just an example right now.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry() {
+        llSetTextureAnim(ANIM_ON | LOOP, ALL_SIDES, 4, 4, 0, 0, 3);
+    } 
+}
+
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/animated_texture_v0.4.txt b/huffware/huffotronic_tools_n_testers_v6.1/animated_texture_v0.4.txt
deleted file mode 100755 (executable)
index 6cc510b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-
-// huffware script: animated texture, by fred huffhines.
-//
-// super simple texture animation, just an example right now.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry() {
-        llSetTextureAnim(ANIM_ON | LOOP, ALL_SIDES, 4, 4, 0, 0, 3);
-    } 
-}
-
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/axis_rider_v2.9.lsl b/huffware/huffotronic_tools_n_testers_v6.1/axis_rider_v2.9.lsl
new file mode 100755 (executable)
index 0000000..c26062c
--- /dev/null
@@ -0,0 +1,324 @@
+
+// huffware script: axis rider, by fred huffhines.
+//
+// causes an object to move up and down on the z axis, although that and
+// other parameters can be modified.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// these two control how far from the original position the object may travel.
+float MIN_POSITION = -0.3;
+float MAX_POSITION = 1.0;
+// these specify which axis to modify and compare on.
+integer USE_X_AXIS = FALSE;
+integer USE_Y_AXIS = FALSE;
+integer USE_Z_AXIS = TRUE;
+// these are the limits on how much the object can move during one timer click.
+float MIN_POSITION_ADJUSTMENT = 0.05;
+float MAX_POSITION_ADJUSTMENT = 0.07;
+
+// jitter is the capability for the object to not be aligned on a straight
+// up and down axis.
+integer JITTER_EFFECT = TRUE;
+    // if this is true, then the rider will move unevenly at various angles.
+float CHANCE_FOR_JITTER = 0.60;
+    // this is the probability of changing the current direction (0.0 to 1.0).
+vector MIN_ANGULAR_POSITION = <0.0, 0.0, 0.0>;  // minimum jitter amount, in degrees.
+vector MAX_ANGULAR_POSITION = <1.0, 1.0, 4.0>;  // maximum jitter amount, in degrees.
+
+float TIMER_FREQUENCY = 0.20;
+    // this is the fastest that prim changes can happen anyhow,
+    // so we fire the timer at this rate.
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
+}
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+// returns TRUE if a is less than b in any component.
+integer vector_less_than(vector a, vector b)
+{ return (a.x < b.x) || (a.y < b.y) || (a.z < b.z); }
+
+// returns TRUE if a is greater than b in any component.
+integer vector_greater_than(vector a, vector b)
+{ return (a.x > b.x) || (a.y > b.y) || (a.z > b.z); }
+
+// returns a list with two components; a new vector and a boolean.
+// the new vector starts from "starting_point".  it will have a vector
+// between "minimum_addition" and "maximum_addition" added to it.
+// if it is over the "minimum_allowed" or the "maximum_allowed", then
+// it is reset to whichever it would have crossed over.  two booleans
+// are also returned to indicate when the lower and upper limits were
+// exceeded (in that order).
+list limit_and_add(vector starting_point,
+    vector minimum_allowed, vector maximum_allowed,
+    vector minimum_addition, vector maximum_addition)
+{
+    integer too_low = FALSE;
+    integer too_high = FALSE;
+    vector new_location = starting_point;
+    vector addition = random_bound_vector(minimum_addition, maximum_addition, FALSE);
+//log_it("start=" + (string)starting_point + " addin=" + (string)addition);
+    new_location += addition;
+    if (vector_less_than(new_location, minimum_allowed)) {
+        too_low = TRUE;
+        new_location = minimum_allowed;
+    } else if (vector_greater_than(new_location, maximum_allowed)) {
+        too_high = TRUE;
+        new_location = maximum_allowed;
+    }
+    return [ new_location, too_low, too_high ];
+}
+
+//////////////
+
+// variables used during the script.
+
+vector rez_position;
+    // set at time of object rez from object's current location.
+
+vector rez_rotation;
+    // set at time of object rez from object's current rotation.
+
+vector current_position_addin = <0.0, 0.0, 0.0>;
+    // the amount that we're adding to the rider's position right now.
+
+vector current_rotation_addin = <0.0, 0.0, 0.0>;
+    // randomly assigned to if JITTER_EFFECT is true.
+
+vector current_direction = <1.0, 1.0, 1.0>;
+    // we start out by adding to all axes.
+
+// provides a random vector that could be negative or positive for
+// any of the values.  the range is given by the two constants
+// MIN_ADDITION and MAX_ADDITION.
+vector rando_vector()
+{
+    return random_bound_vector(MIN_ANGULAR_POSITION * DEG_TO_RAD,
+        MAX_ANGULAR_POSITION * DEG_TO_RAD, TRUE);
+}
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        rez_position = llGetPos();
+        rez_rotation = llRot2Euler(llGetRot());
+//vector calc_rot = rez_rotation * RAD_TO_DEG;
+//log_it("rotation at start is " + (string)calc_rot);
+        llSetTimerEvent(TIMER_FREQUENCY);
+    }
+    
+    on_rez(integer parm) { llResetScript(); }
+
+    timer()
+    {
+        if (USE_X_AXIS) {
+             list add_result = limit_and_add(current_position_addin,
+                <MIN_POSITION, current_position_addin.y, current_position_addin.z>,
+                <MAX_POSITION, current_position_addin.y, current_position_addin.z>,
+                <current_direction.x * MIN_POSITION_ADJUSTMENT, 0.0, 0.0>,
+                <current_direction.x * MAX_POSITION_ADJUSTMENT, 0.0, 0.0>);
+            current_position_addin = llList2Vector(add_result, 0);
+            integer too_low = llList2Integer(add_result, 1);
+            integer too_high = llList2Integer(add_result, 2);
+            if (too_low) current_direction.x = 1.0;
+            else if (too_high) current_direction.x = -1.0;
+        }
+        if (USE_Y_AXIS) {
+             list add_result = limit_and_add(current_position_addin,
+                <current_position_addin.x, MIN_POSITION, current_position_addin.z>,
+                <current_position_addin.x, MAX_POSITION, current_position_addin.z>,
+                <0.0, current_direction.y * MIN_POSITION_ADJUSTMENT, 0.0>,
+                <0.0, current_direction.y * MAX_POSITION_ADJUSTMENT, 0.0>);
+            current_position_addin = llList2Vector(add_result, 0);
+            integer too_low = llList2Integer(add_result, 1);
+            integer too_high = llList2Integer(add_result, 2);
+            if (too_low) current_direction.y = 1.0;
+            else if (too_high) current_direction.y = -1.0;
+        }
+        if (USE_Z_AXIS) {
+             list add_result = limit_and_add(current_position_addin,
+                <current_position_addin.x, current_position_addin.y, MIN_POSITION>,
+                <current_position_addin.x, current_position_addin.y, MAX_POSITION>,
+                <0.0, 0.0, current_direction.z * MIN_POSITION_ADJUSTMENT>,
+                <0.0, 0.0, current_direction.z * MAX_POSITION_ADJUSTMENT>);
+            current_position_addin = llList2Vector(add_result, 0);
+            integer too_low = llList2Integer(add_result, 1);
+            integer too_high = llList2Integer(add_result, 2);
+            if (too_low) current_direction.z = 1.0;
+            else if (too_high) current_direction.z = -1.0;
+        }
+        
+//logic below for randomness is a bit odd.
+        // change the jitter position if we get a chance.
+        float starter = 0.420;  // where we start looking for change.
+        float change_cap = starter + CHANCE_FOR_JITTER;
+        float randomness = llFrand(1.000);
+        if ( (randomness <= change_cap) && (randomness >= starter) ) {
+            // time for a change in the rotation.
+            if (JITTER_EFFECT) {
+                current_rotation_addin = rando_vector();
+            }
+        }
+
+        llSetPrimitiveParams([
+            PRIM_POSITION, rez_position + current_position_addin,
+            PRIM_ROTATION, llEuler2Rot(rez_rotation + current_rotation_addin)
+            ]);
+
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/axis_rider_v2.9.txt b/huffware/huffotronic_tools_n_testers_v6.1/axis_rider_v2.9.txt
deleted file mode 100755 (executable)
index c26062c..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-
-// huffware script: axis rider, by fred huffhines.
-//
-// causes an object to move up and down on the z axis, although that and
-// other parameters can be modified.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// these two control how far from the original position the object may travel.
-float MIN_POSITION = -0.3;
-float MAX_POSITION = 1.0;
-// these specify which axis to modify and compare on.
-integer USE_X_AXIS = FALSE;
-integer USE_Y_AXIS = FALSE;
-integer USE_Z_AXIS = TRUE;
-// these are the limits on how much the object can move during one timer click.
-float MIN_POSITION_ADJUSTMENT = 0.05;
-float MAX_POSITION_ADJUSTMENT = 0.07;
-
-// jitter is the capability for the object to not be aligned on a straight
-// up and down axis.
-integer JITTER_EFFECT = TRUE;
-    // if this is true, then the rider will move unevenly at various angles.
-float CHANCE_FOR_JITTER = 0.60;
-    // this is the probability of changing the current direction (0.0 to 1.0).
-vector MIN_ANGULAR_POSITION = <0.0, 0.0, 0.0>;  // minimum jitter amount, in degrees.
-vector MAX_ANGULAR_POSITION = <1.0, 1.0, 4.0>;  // maximum jitter amount, in degrees.
-
-float TIMER_FREQUENCY = 0.20;
-    // this is the fastest that prim changes can happen anyhow,
-    // so we fire the timer at this rate.
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
-}
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-// returns TRUE if a is less than b in any component.
-integer vector_less_than(vector a, vector b)
-{ return (a.x < b.x) || (a.y < b.y) || (a.z < b.z); }
-
-// returns TRUE if a is greater than b in any component.
-integer vector_greater_than(vector a, vector b)
-{ return (a.x > b.x) || (a.y > b.y) || (a.z > b.z); }
-
-// returns a list with two components; a new vector and a boolean.
-// the new vector starts from "starting_point".  it will have a vector
-// between "minimum_addition" and "maximum_addition" added to it.
-// if it is over the "minimum_allowed" or the "maximum_allowed", then
-// it is reset to whichever it would have crossed over.  two booleans
-// are also returned to indicate when the lower and upper limits were
-// exceeded (in that order).
-list limit_and_add(vector starting_point,
-    vector minimum_allowed, vector maximum_allowed,
-    vector minimum_addition, vector maximum_addition)
-{
-    integer too_low = FALSE;
-    integer too_high = FALSE;
-    vector new_location = starting_point;
-    vector addition = random_bound_vector(minimum_addition, maximum_addition, FALSE);
-//log_it("start=" + (string)starting_point + " addin=" + (string)addition);
-    new_location += addition;
-    if (vector_less_than(new_location, minimum_allowed)) {
-        too_low = TRUE;
-        new_location = minimum_allowed;
-    } else if (vector_greater_than(new_location, maximum_allowed)) {
-        too_high = TRUE;
-        new_location = maximum_allowed;
-    }
-    return [ new_location, too_low, too_high ];
-}
-
-//////////////
-
-// variables used during the script.
-
-vector rez_position;
-    // set at time of object rez from object's current location.
-
-vector rez_rotation;
-    // set at time of object rez from object's current rotation.
-
-vector current_position_addin = <0.0, 0.0, 0.0>;
-    // the amount that we're adding to the rider's position right now.
-
-vector current_rotation_addin = <0.0, 0.0, 0.0>;
-    // randomly assigned to if JITTER_EFFECT is true.
-
-vector current_direction = <1.0, 1.0, 1.0>;
-    // we start out by adding to all axes.
-
-// provides a random vector that could be negative or positive for
-// any of the values.  the range is given by the two constants
-// MIN_ADDITION and MAX_ADDITION.
-vector rando_vector()
-{
-    return random_bound_vector(MIN_ANGULAR_POSITION * DEG_TO_RAD,
-        MAX_ANGULAR_POSITION * DEG_TO_RAD, TRUE);
-}
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        rez_position = llGetPos();
-        rez_rotation = llRot2Euler(llGetRot());
-//vector calc_rot = rez_rotation * RAD_TO_DEG;
-//log_it("rotation at start is " + (string)calc_rot);
-        llSetTimerEvent(TIMER_FREQUENCY);
-    }
-    
-    on_rez(integer parm) { llResetScript(); }
-
-    timer()
-    {
-        if (USE_X_AXIS) {
-             list add_result = limit_and_add(current_position_addin,
-                <MIN_POSITION, current_position_addin.y, current_position_addin.z>,
-                <MAX_POSITION, current_position_addin.y, current_position_addin.z>,
-                <current_direction.x * MIN_POSITION_ADJUSTMENT, 0.0, 0.0>,
-                <current_direction.x * MAX_POSITION_ADJUSTMENT, 0.0, 0.0>);
-            current_position_addin = llList2Vector(add_result, 0);
-            integer too_low = llList2Integer(add_result, 1);
-            integer too_high = llList2Integer(add_result, 2);
-            if (too_low) current_direction.x = 1.0;
-            else if (too_high) current_direction.x = -1.0;
-        }
-        if (USE_Y_AXIS) {
-             list add_result = limit_and_add(current_position_addin,
-                <current_position_addin.x, MIN_POSITION, current_position_addin.z>,
-                <current_position_addin.x, MAX_POSITION, current_position_addin.z>,
-                <0.0, current_direction.y * MIN_POSITION_ADJUSTMENT, 0.0>,
-                <0.0, current_direction.y * MAX_POSITION_ADJUSTMENT, 0.0>);
-            current_position_addin = llList2Vector(add_result, 0);
-            integer too_low = llList2Integer(add_result, 1);
-            integer too_high = llList2Integer(add_result, 2);
-            if (too_low) current_direction.y = 1.0;
-            else if (too_high) current_direction.y = -1.0;
-        }
-        if (USE_Z_AXIS) {
-             list add_result = limit_and_add(current_position_addin,
-                <current_position_addin.x, current_position_addin.y, MIN_POSITION>,
-                <current_position_addin.x, current_position_addin.y, MAX_POSITION>,
-                <0.0, 0.0, current_direction.z * MIN_POSITION_ADJUSTMENT>,
-                <0.0, 0.0, current_direction.z * MAX_POSITION_ADJUSTMENT>);
-            current_position_addin = llList2Vector(add_result, 0);
-            integer too_low = llList2Integer(add_result, 1);
-            integer too_high = llList2Integer(add_result, 2);
-            if (too_low) current_direction.z = 1.0;
-            else if (too_high) current_direction.z = -1.0;
-        }
-        
-//logic below for randomness is a bit odd.
-        // change the jitter position if we get a chance.
-        float starter = 0.420;  // where we start looking for change.
-        float change_cap = starter + CHANCE_FOR_JITTER;
-        float randomness = llFrand(1.000);
-        if ( (randomness <= change_cap) && (randomness >= starter) ) {
-            // time for a change in the rotation.
-            if (JITTER_EFFECT) {
-                current_rotation_addin = rando_vector();
-            }
-        }
-
-        llSetPrimitiveParams([
-            PRIM_POSITION, rez_position + current_position_addin,
-            PRIM_ROTATION, llEuler2Rot(rez_rotation + current_rotation_addin)
-            ]);
-
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/base_note_read_v0.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/base_note_read_v0.3.lsl
new file mode 100755 (executable)
index 0000000..23a39dc
--- /dev/null
@@ -0,0 +1,217 @@
+
+// add-in...  huffware script: notecard library, by fred huffhines
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// items controlled by the notecard...
+
+string NOTECARD_SIGNATURE = "#hoopy";  // the first line of the notecard must be this.
+
+string current_notecard_name = "";  // the name of the card we're reading now.
+key current_query_id = NULL_KEY;  // the query ID for the current notecard.
+list query_contents;  // the lines we have read from the notecard.
+integer line_number;  // which line are we at in notecard?
+integer debug = FALSE;
+
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+    
+initialize()
+{
+    // we keep the same notecard name, in case it's still good.  we want to
+    // avoid re-reading the notecard unless we see an inventory change.
+    current_query_id = NULL_KEY;
+    query_contents = [];
+    line_number = 0;
+}
+
+// returns a non-empty string if "to_check" defines contents for "variable_name".
+string defines_variable(string to_check, string variable_name)
+{
+    // clean initial spaces.
+    while (llGetSubString(to_check, 0, 0) == " ")
+        to_check = llDeleteSubString(to_check, 0, 0);
+    if (!is_prefix(to_check, variable_name)) return "";
+    to_check = llDeleteSubString(to_check, 0, llStringLength(variable_name) - 1);
+    // clean any spaces or valid assignment characters.
+    while ( (llGetSubString(to_check, 0, 0) == " ")
+            || (llGetSubString(to_check, 0, 0) == "=")
+            || (llGetSubString(to_check, 0, 0) == ",") )
+        to_check = llDeleteSubString(to_check, 0, 0);
+    if (debug)
+        log_it("set " + variable_name + " = " + to_check);    
+    // return what's left of the string.
+    return to_check;
+}
+
+parse_variable_definition(string to_parse)
+{
+    string content;  // filled after finding a variable name.
+    string texture_name;  // temporary used in reading texture name.
+
+//etc.    
+//    if ( (content = defines_variable(to_parse, "debug")) != "")
+//        debug = (integer)content;
+
+}
+
+process_particle_settings(list particle_definitions)
+{
+    integer current_item = 0;
+    integer max_items = llGetListLength(particle_definitions);
+    while (current_item < max_items) {
+        string curr_line = llList2String(particle_definitions, current_item);
+        parse_variable_definition(curr_line);
+        current_item++;
+    }
+}
+
+check_for_notecard()
+{
+    if (current_notecard_name != "") return;
+    current_notecard_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
+    // if the notecard is real, then we will start reading it.
+    if (current_notecard_name != "") {
+        line_number = 0;
+        query_contents = [];
+        current_query_id = llGetNotecardLine(current_notecard_name, 0);
+    }
+}
+
+//////////////
+// from hufflets...
+
+//////////////
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+//////////////
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+
+// handles when blank strings need to come through the pipe.
+string wrap_blank_string(string to_wrap)
+{
+    if (llStringLength(to_wrap)) return to_wrap;  // that one is okay.
+    return "\"\"";  // return a quoted nothing as a signal for a blank.
+}
+
+// undoes a previously wrapped blank string.
+string interpret_blank_string(string to_unwrap)
+{
+    if (to_unwrap == "\"\"") return "";  // that was an encoded blank.
+    return to_unwrap;  // no encoding.
+}
+
+//////////////
+
+// returns a number at most maximum and at least minimum.
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// the string processing methods are not case sensitive.
+  
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+//        auto_retire();
+        initialize();
+        check_for_notecard();
+    }
+
+    changed(integer change_type) {
+        if (change_type != CHANGED_INVENTORY) {
+            // we only care about inventory changes here.
+            return;
+        }
+        if (current_query_id != NULL_KEY) {
+            // we're already reading a card right now.
+            return;
+        }
+        // make sure we reset the old name.
+        current_notecard_name = "";
+        check_for_notecard();
+    }
+    
+    dataserver(key query_id, string data) {
+        if (query_id != current_query_id) {
+log_it("not our query id somehow?");
+//log_it("weird query had: " + (string)data);
+            return;
+        }
+        // if we're not at the end of the notecard we're reading...
+        if (data != EOF) {
+            if (!line_number) {
+                if (data != NOTECARD_SIGNATURE) {
+                    // this card has the wrong signature at the top.  quit bothering
+                    // with it now.
+                    return;
+                }
+                log_it("starting to read notecard " + current_notecard_name + "...");    
+            }
+            if (data != "") {
+                 // add the non-blank line to our destination list.
+                query_contents += data;
+//log_it("line " + (string)line_number + ": data=" + data);
+            }
+            line_number++;  // increase the line count.
+            // request the next line from the notecard.
+            current_query_id = llGetNotecardLine(current_notecard_name, line_number);
+        } else {
+            // no more data, so we're done with this card.
+            current_query_id = NULL_KEY;
+            if (!llGetListLength(query_contents)) {
+                // nothing was read?  the heck with this card.
+                current_notecard_name = "";  // toss bad card.
+                return;
+            }
+log_it("notecard said:\n" + (string)(query_contents));
+            log_it("done reading notecard " + current_notecard_name + ".");
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/base_note_read_v0.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/base_note_read_v0.3.txt
deleted file mode 100755 (executable)
index 23a39dc..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-
-// add-in...  huffware script: notecard library, by fred huffhines
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// items controlled by the notecard...
-
-string NOTECARD_SIGNATURE = "#hoopy";  // the first line of the notecard must be this.
-
-string current_notecard_name = "";  // the name of the card we're reading now.
-key current_query_id = NULL_KEY;  // the query ID for the current notecard.
-list query_contents;  // the lines we have read from the notecard.
-integer line_number;  // which line are we at in notecard?
-integer debug = FALSE;
-
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-    
-initialize()
-{
-    // we keep the same notecard name, in case it's still good.  we want to
-    // avoid re-reading the notecard unless we see an inventory change.
-    current_query_id = NULL_KEY;
-    query_contents = [];
-    line_number = 0;
-}
-
-// returns a non-empty string if "to_check" defines contents for "variable_name".
-string defines_variable(string to_check, string variable_name)
-{
-    // clean initial spaces.
-    while (llGetSubString(to_check, 0, 0) == " ")
-        to_check = llDeleteSubString(to_check, 0, 0);
-    if (!is_prefix(to_check, variable_name)) return "";
-    to_check = llDeleteSubString(to_check, 0, llStringLength(variable_name) - 1);
-    // clean any spaces or valid assignment characters.
-    while ( (llGetSubString(to_check, 0, 0) == " ")
-            || (llGetSubString(to_check, 0, 0) == "=")
-            || (llGetSubString(to_check, 0, 0) == ",") )
-        to_check = llDeleteSubString(to_check, 0, 0);
-    if (debug)
-        log_it("set " + variable_name + " = " + to_check);    
-    // return what's left of the string.
-    return to_check;
-}
-
-parse_variable_definition(string to_parse)
-{
-    string content;  // filled after finding a variable name.
-    string texture_name;  // temporary used in reading texture name.
-
-//etc.    
-//    if ( (content = defines_variable(to_parse, "debug")) != "")
-//        debug = (integer)content;
-
-}
-
-process_particle_settings(list particle_definitions)
-{
-    integer current_item = 0;
-    integer max_items = llGetListLength(particle_definitions);
-    while (current_item < max_items) {
-        string curr_line = llList2String(particle_definitions, current_item);
-        parse_variable_definition(curr_line);
-        current_item++;
-    }
-}
-
-check_for_notecard()
-{
-    if (current_notecard_name != "") return;
-    current_notecard_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
-    // if the notecard is real, then we will start reading it.
-    if (current_notecard_name != "") {
-        line_number = 0;
-        query_contents = [];
-        current_query_id = llGetNotecardLine(current_notecard_name, 0);
-    }
-}
-
-//////////////
-// from hufflets...
-
-//////////////
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-//////////////
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-
-// handles when blank strings need to come through the pipe.
-string wrap_blank_string(string to_wrap)
-{
-    if (llStringLength(to_wrap)) return to_wrap;  // that one is okay.
-    return "\"\"";  // return a quoted nothing as a signal for a blank.
-}
-
-// undoes a previously wrapped blank string.
-string interpret_blank_string(string to_unwrap)
-{
-    if (to_unwrap == "\"\"") return "";  // that was an encoded blank.
-    return to_unwrap;  // no encoding.
-}
-
-//////////////
-
-// returns a number at most maximum and at least minimum.
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// the string processing methods are not case sensitive.
-  
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-//        auto_retire();
-        initialize();
-        check_for_notecard();
-    }
-
-    changed(integer change_type) {
-        if (change_type != CHANGED_INVENTORY) {
-            // we only care about inventory changes here.
-            return;
-        }
-        if (current_query_id != NULL_KEY) {
-            // we're already reading a card right now.
-            return;
-        }
-        // make sure we reset the old name.
-        current_notecard_name = "";
-        check_for_notecard();
-    }
-    
-    dataserver(key query_id, string data) {
-        if (query_id != current_query_id) {
-log_it("not our query id somehow?");
-//log_it("weird query had: " + (string)data);
-            return;
-        }
-        // if we're not at the end of the notecard we're reading...
-        if (data != EOF) {
-            if (!line_number) {
-                if (data != NOTECARD_SIGNATURE) {
-                    // this card has the wrong signature at the top.  quit bothering
-                    // with it now.
-                    return;
-                }
-                log_it("starting to read notecard " + current_notecard_name + "...");    
-            }
-            if (data != "") {
-                 // add the non-blank line to our destination list.
-                query_contents += data;
-//log_it("line " + (string)line_number + ": data=" + data);
-            }
-            line_number++;  // increase the line count.
-            // request the next line from the notecard.
-            current_query_id = llGetNotecardLine(current_notecard_name, line_number);
-        } else {
-            // no more data, so we're done with this card.
-            current_query_id = NULL_KEY;
-            if (!llGetListLength(query_contents)) {
-                // nothing was read?  the heck with this card.
-                current_notecard_name = "";  // toss bad card.
-                return;
-            }
-log_it("notecard said:\n" + (string)(query_contents));
-            log_it("done reading notecard " + current_notecard_name + ".");
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/begging_bowl_v4.4.lsl b/huffware/huffotronic_tools_n_testers_v6.1/begging_bowl_v4.4.lsl
new file mode 100755 (executable)
index 0000000..2f6c27b
--- /dev/null
@@ -0,0 +1,229 @@
+
+// huffware script: begging bowl, by fred huffhines.
+//
+// handles gifts from visitors at our shop.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants.
+
+integer BEGGING_INTERVAL = 8;
+    // the period (in seconds) of our asking the avatar for money.
+    // keeping this reasonably high ensures that the begging jar isn't
+    // too noisy if someone is whanging away at it to play the sound or
+    // see the explosion.
+
+// variables, some with initializers.
+
+integer last_begging_time;  // when we last pleaded for additional funding.
+
+integer tip_amount;  // the amount given to us just recently.
+integer total_tips = 638;
+    // 108 -- aug 30 2008 or so.  214 -- nov 28 2008.  342 -- dec 28 2008.
+    // 486 -- mar 21 2009.  589 -- may 12 2009.  632 -- aug 02 2009.
+    // 638 -- aug 31 2009.
+key tippers_key = NULL_KEY;  // the key for the avatar that has tipped us.
+string last_tipper;  // the name of the last tipper.
+
+show_label()
+{
+    string msg = "{ eepaw tipster }\ntouch for more info...\n.\nL$"
+        + (string)total_tips + " donated so far--thanks!";
+    if (last_tipper != "")
+        msg += "\nLast recvd L$" + (string)tip_amount + " from " + last_tipper + ", yay!";
+    llSetText(msg, <0.8, 0.6, 0.9>, 1);
+}
+
+initialize_begging_bowl()
+{
+    show_label();
+    llOwnerSay("ready to receive tips from customers...");
+    llParticleSystem([]);
+    last_begging_time = llGetUnixTime();  // reset just to have some kindo value.
+    show_label();
+}
+
+thank_tipper_and_give_gifts(string name)
+{
+    llSay(0, "eepaw shop and its workers thank you for the tip, " + name + "!");
+    last_tipper = name;  // store this for our text.
+    string first_name = llDeleteSubString(name, llSubStringIndex(name, " "), -1);
+    llInstantMessage(tippers_key, first_name + ", thank you very much for your tip of L$"
+        + (string)tip_amount + ", from all of us at eepaw shop.");
+    llOwnerSay("received tip from " + name + " of L$" + (string)tip_amount + ".");
+    if (llGetInventoryNumber(INVENTORY_SOUND)) {
+        // we will only play one sound currently.
+        llPlaySound(llGetInventoryName(INVENTORY_SOUND, 0 ), 1.0);
+    }
+    
+    // give out pictures, notecards and objects that are hiding in the object.
+    integer indy;
+    list all_to_give;  // the full set of gifts.    
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_TEXTURE); indy++) 
+        all_to_give += llGetInventoryName(INVENTORY_TEXTURE, indy);
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_NOTECARD); indy++) 
+        all_to_give += llGetInventoryName(INVENTORY_NOTECARD, indy);
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_OBJECT); indy++)
+        all_to_give += llGetInventoryName(INVENTORY_OBJECT, indy);
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_OBJECT); indy++)
+        all_to_give += llGetInventoryName(INVENTORY_SOUND, indy);
+    // pick a semi-meaningful folder name.
+    string gift_folder_name = "eepaw thanky! (you gave us L$"
+        + (string)tip_amount + " on " + llGetDate() + ")";
+    // then gift it over.
+    llGiveInventoryList(tippers_key, gift_folder_name, all_to_give);
+    // record the tip.    
+    total_tips += tip_amount;
+    llOwnerSay("tips so far: L$" + (string)total_tips + ".");
+    show_label();  // refresh our text label.
+}
+
+handle_being_touched(integer num) {
+    // make sure we've waited enough time before begging again.
+    if (llAbs(llGetUnixTime() - last_begging_time) > BEGGING_INTERVAL) {
+        llSay(0,
+            "\nIt would be awesome if you could tip our hardworking widget gnomes.\n"
+            + "If you right-click this object, you can 'Pay' it a tip, which will\n"
+            + "go directly to the eepaw shop personnel.  Thanks much!");
+        // update our last begging time so we don't beg too often.
+        last_begging_time = llGetUnixTime();
+    }
+    // explode the textures just a little bit, if we have any on hand.
+    integer indy;
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_TEXTURE); indy++) {
+        llMakeExplosion(14, .4, 0.5, 4, 0.8,
+            llGetInventoryName(INVENTORY_TEXTURE, indy), <0.0, 0.0, 0.0>);
+    }
+    // play the last sound that we happen to have, if any at all.
+    llPlaySound(llGetInventoryName(INVENTORY_SOUND, llGetInventoryNumber(INVENTORY_SOUND) - 1), 1.0);
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { 
+        auto_retire();
+        initialize_begging_bowl();
+    }
+
+    touch_start(integer num) {
+        handle_being_touched(num);
+    }
+
+    money(key id, integer payment) {
+        tip_amount = payment;
+        tippers_key = id;
+        llRequestAgentData(id, DATA_NAME);
+    }
+
+    dataserver(key query, string name) { thank_tipper_and_give_gifts(name); }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/begging_bowl_v4.4.txt b/huffware/huffotronic_tools_n_testers_v6.1/begging_bowl_v4.4.txt
deleted file mode 100755 (executable)
index 2f6c27b..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-
-// huffware script: begging bowl, by fred huffhines.
-//
-// handles gifts from visitors at our shop.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants.
-
-integer BEGGING_INTERVAL = 8;
-    // the period (in seconds) of our asking the avatar for money.
-    // keeping this reasonably high ensures that the begging jar isn't
-    // too noisy if someone is whanging away at it to play the sound or
-    // see the explosion.
-
-// variables, some with initializers.
-
-integer last_begging_time;  // when we last pleaded for additional funding.
-
-integer tip_amount;  // the amount given to us just recently.
-integer total_tips = 638;
-    // 108 -- aug 30 2008 or so.  214 -- nov 28 2008.  342 -- dec 28 2008.
-    // 486 -- mar 21 2009.  589 -- may 12 2009.  632 -- aug 02 2009.
-    // 638 -- aug 31 2009.
-key tippers_key = NULL_KEY;  // the key for the avatar that has tipped us.
-string last_tipper;  // the name of the last tipper.
-
-show_label()
-{
-    string msg = "{ eepaw tipster }\ntouch for more info...\n.\nL$"
-        + (string)total_tips + " donated so far--thanks!";
-    if (last_tipper != "")
-        msg += "\nLast recvd L$" + (string)tip_amount + " from " + last_tipper + ", yay!";
-    llSetText(msg, <0.8, 0.6, 0.9>, 1);
-}
-
-initialize_begging_bowl()
-{
-    show_label();
-    llOwnerSay("ready to receive tips from customers...");
-    llParticleSystem([]);
-    last_begging_time = llGetUnixTime();  // reset just to have some kindo value.
-    show_label();
-}
-
-thank_tipper_and_give_gifts(string name)
-{
-    llSay(0, "eepaw shop and its workers thank you for the tip, " + name + "!");
-    last_tipper = name;  // store this for our text.
-    string first_name = llDeleteSubString(name, llSubStringIndex(name, " "), -1);
-    llInstantMessage(tippers_key, first_name + ", thank you very much for your tip of L$"
-        + (string)tip_amount + ", from all of us at eepaw shop.");
-    llOwnerSay("received tip from " + name + " of L$" + (string)tip_amount + ".");
-    if (llGetInventoryNumber(INVENTORY_SOUND)) {
-        // we will only play one sound currently.
-        llPlaySound(llGetInventoryName(INVENTORY_SOUND, 0 ), 1.0);
-    }
-    
-    // give out pictures, notecards and objects that are hiding in the object.
-    integer indy;
-    list all_to_give;  // the full set of gifts.    
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_TEXTURE); indy++) 
-        all_to_give += llGetInventoryName(INVENTORY_TEXTURE, indy);
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_NOTECARD); indy++) 
-        all_to_give += llGetInventoryName(INVENTORY_NOTECARD, indy);
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_OBJECT); indy++)
-        all_to_give += llGetInventoryName(INVENTORY_OBJECT, indy);
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_OBJECT); indy++)
-        all_to_give += llGetInventoryName(INVENTORY_SOUND, indy);
-    // pick a semi-meaningful folder name.
-    string gift_folder_name = "eepaw thanky! (you gave us L$"
-        + (string)tip_amount + " on " + llGetDate() + ")";
-    // then gift it over.
-    llGiveInventoryList(tippers_key, gift_folder_name, all_to_give);
-    // record the tip.    
-    total_tips += tip_amount;
-    llOwnerSay("tips so far: L$" + (string)total_tips + ".");
-    show_label();  // refresh our text label.
-}
-
-handle_being_touched(integer num) {
-    // make sure we've waited enough time before begging again.
-    if (llAbs(llGetUnixTime() - last_begging_time) > BEGGING_INTERVAL) {
-        llSay(0,
-            "\nIt would be awesome if you could tip our hardworking widget gnomes.\n"
-            + "If you right-click this object, you can 'Pay' it a tip, which will\n"
-            + "go directly to the eepaw shop personnel.  Thanks much!");
-        // update our last begging time so we don't beg too often.
-        last_begging_time = llGetUnixTime();
-    }
-    // explode the textures just a little bit, if we have any on hand.
-    integer indy;
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_TEXTURE); indy++) {
-        llMakeExplosion(14, .4, 0.5, 4, 0.8,
-            llGetInventoryName(INVENTORY_TEXTURE, indy), <0.0, 0.0, 0.0>);
-    }
-    // play the last sound that we happen to have, if any at all.
-    llPlaySound(llGetInventoryName(INVENTORY_SOUND, llGetInventoryNumber(INVENTORY_SOUND) - 1), 1.0);
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { 
-        auto_retire();
-        initialize_begging_bowl();
-    }
-
-    touch_start(integer num) {
-        handle_being_touched(num);
-    }
-
-    money(key id, integer payment) {
-        tip_amount = payment;
-        tippers_key = id;
-        llRequestAgentData(id, DATA_NAME);
-    }
-
-    dataserver(key query, string name) { thank_tipper_and_give_gifts(name); }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/bouncer_v2.0.lsl b/huffware/huffotronic_tools_n_testers_v6.1/bouncer_v2.0.lsl
new file mode 100755 (executable)
index 0000000..e91d410
--- /dev/null
@@ -0,0 +1,206 @@
+
+// huffware script: bouncer, by fred huffhines.
+//
+// this script repels an object or avatar that slams into it.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer PUSH_UPWARDS = TRUE;
+    // if this is true, the velocity is reflected upwards.  this is sort of
+    // a trampoline effect.
+integer PUSH_DIRECTLY_BACK = TRUE;
+    // if this is true, then the object's velocity is reflected directly back.
+    // this is not a realistic bounce since it is like every bounce hits the
+    // object at a tangent rather than having the angle be rotated as a
+    // reflection.
+
+integer AVATARS_ONLY = FALSE;
+    // if true, then the bouncer will only react to people and not things.
+
+float PUSH_MULTIPLIER = 32.0;
+    // increase the object's velocity by this factor, as part of how we
+    // help it along when it collides with us.
+
+integer LOCAL_AXIS = FALSE;
+    // use the axis relative to the object's rotation?
+
+// originally came from reverse_velocity from concussive script.
+push_back(key act_upon, integer local_axis)
+{
+    list details = llGetObjectDetails(act_upon, [ OBJECT_VELOCITY ]);
+    vector current_velocity = llList2Vector(details, 0);    
+
+    if (local_axis) {
+        rotation rot = llGetRot();
+        current_velocity /= rot;  // undo the rotation.
+    }
+    // here's where we return the velocity exactly backwards along
+    // its own axis.  this is not really very true to physics.
+    vector new_velocity = -PUSH_MULTIPLIER * current_velocity;
+    new_velocity *= llGetMass();
+    llPushObject(act_upon, new_velocity, ZERO_VECTOR, local_axis);
+}
+
+// causes the object to be thrown up into the air and magnifies their
+// velocity.
+push_up(key act_upon, integer local_axis)
+{
+    list details = llGetObjectDetails(act_upon, [ OBJECT_VELOCITY ]);
+    vector current_velocity = llList2Vector(details, 0);
+    if (local_axis) {
+        rotation rot = llGetRot();
+        current_velocity /= rot;  // undo the rotation.
+    }
+    // another example that's like the trampoline...
+//    vector new_velocity = PUSH_MULTIPLIER * llRot2Up(llGetRot());
+    vector new_velocity = current_velocity;
+    new_velocity.z = -PUSH_MULTIPLIER * new_velocity.z;
+    new_velocity *= llGetMass();
+    llPushObject(act_upon, new_velocity, ZERO_VECTOR, local_axis);
+}
+
+// a newer method that can be used to 'continue' the velocity away from
+// the bouncer but more upwards from an elastic collision than back at the av.
+/////not implemented yet.
+// needs good physics normal vector implementation.
+
+// called by the collision event handler when we detect something
+// bumping into us.
+handle_collisions(integer count)
+{
+    integer i;
+    for (i = 0; i < count; i++) {
+        if ( (AVATARS_ONLY && (llDetectedType(i) & AGENT) )
+                || !AVATARS_ONLY) {
+            if (PUSH_UPWARDS)
+                push_up(llDetectedKey(i), LOCAL_AXIS);
+            if (PUSH_DIRECTLY_BACK)
+                push_back(llDetectedKey(i), LOCAL_AXIS);
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); }
+
+    collision(integer count) { handle_collisions(count); }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/bouncer_v2.0.txt b/huffware/huffotronic_tools_n_testers_v6.1/bouncer_v2.0.txt
deleted file mode 100755 (executable)
index e91d410..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-
-// huffware script: bouncer, by fred huffhines.
-//
-// this script repels an object or avatar that slams into it.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer PUSH_UPWARDS = TRUE;
-    // if this is true, the velocity is reflected upwards.  this is sort of
-    // a trampoline effect.
-integer PUSH_DIRECTLY_BACK = TRUE;
-    // if this is true, then the object's velocity is reflected directly back.
-    // this is not a realistic bounce since it is like every bounce hits the
-    // object at a tangent rather than having the angle be rotated as a
-    // reflection.
-
-integer AVATARS_ONLY = FALSE;
-    // if true, then the bouncer will only react to people and not things.
-
-float PUSH_MULTIPLIER = 32.0;
-    // increase the object's velocity by this factor, as part of how we
-    // help it along when it collides with us.
-
-integer LOCAL_AXIS = FALSE;
-    // use the axis relative to the object's rotation?
-
-// originally came from reverse_velocity from concussive script.
-push_back(key act_upon, integer local_axis)
-{
-    list details = llGetObjectDetails(act_upon, [ OBJECT_VELOCITY ]);
-    vector current_velocity = llList2Vector(details, 0);    
-
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    // here's where we return the velocity exactly backwards along
-    // its own axis.  this is not really very true to physics.
-    vector new_velocity = -PUSH_MULTIPLIER * current_velocity;
-    new_velocity *= llGetMass();
-    llPushObject(act_upon, new_velocity, ZERO_VECTOR, local_axis);
-}
-
-// causes the object to be thrown up into the air and magnifies their
-// velocity.
-push_up(key act_upon, integer local_axis)
-{
-    list details = llGetObjectDetails(act_upon, [ OBJECT_VELOCITY ]);
-    vector current_velocity = llList2Vector(details, 0);
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    // another example that's like the trampoline...
-//    vector new_velocity = PUSH_MULTIPLIER * llRot2Up(llGetRot());
-    vector new_velocity = current_velocity;
-    new_velocity.z = -PUSH_MULTIPLIER * new_velocity.z;
-    new_velocity *= llGetMass();
-    llPushObject(act_upon, new_velocity, ZERO_VECTOR, local_axis);
-}
-
-// a newer method that can be used to 'continue' the velocity away from
-// the bouncer but more upwards from an elastic collision than back at the av.
-/////not implemented yet.
-// needs good physics normal vector implementation.
-
-// called by the collision event handler when we detect something
-// bumping into us.
-handle_collisions(integer count)
-{
-    integer i;
-    for (i = 0; i < count; i++) {
-        if ( (AVATARS_ONLY && (llDetectedType(i) & AGENT) )
-                || !AVATARS_ONLY) {
-            if (PUSH_UPWARDS)
-                push_up(llDetectedKey(i), LOCAL_AXIS);
-            if (PUSH_DIRECTLY_BACK)
-                push_back(llDetectedKey(i), LOCAL_AXIS);
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); }
-
-    collision(integer count) { handle_collisions(count); }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/box_mover_v1.7.lsl b/huffware/huffotronic_tools_n_testers_v6.1/box_mover_v1.7.lsl
new file mode 100755 (executable)
index 0000000..cd297f2
--- /dev/null
@@ -0,0 +1,188 @@
+
+// huffware script: box mover, by fred huffhines.
+//
+// a really simple script to make a box jump out of one's way.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+
+//hmmm: fix this to use a notecard for dimensions and members.
+
+
+// modifiable constants.
+
+vector jump_offset = <4.0, -3.0, 0.0>;  // how far to jump away from the starting place.
+
+list allowed_avatars = [ "fred huffhines", "Chronical Koolhoven", "Mojopickle Haystack",
+    "Zeno Olifone", "After9 NightFire", "Wam7c Macchi" ];
+
+// variables below.
+
+vector home;  // where do we live normally?
+
+// makes our list of allowed keys into uniform lower case.
+fix_list_items()
+{
+    integer i;
+    list fixed_list;
+    for (i = 0; i < llGetListLength(allowed_avatars); i++) {
+        string curr = llList2String(allowed_avatars, i);
+        curr = llToLower(curr);
+        fixed_list += [curr];
+    }
+    allowed_avatars = fixed_list;
+//llOwnerSay("got a new list of: " + (string)allowed_avatars);    
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();  // make sure newest addition is only version of script.
+        fix_list_items();  // make sure entries are lower case.
+        home = llGetPos();
+    }
+    
+    touch_start(integer total_number) {
+llOwnerSay("touched by " + llDetectedName(0));
+        // if we're not the owner, then we've got a few extra requirements before
+        // we do anything at all.
+        if (llDetectedKey(0) != llGetOwner()) {
+            list lowname = [ llToLower(llDetectedName(0)) ];
+            if (llListFindList(allowed_avatars, lowname) < 0) {
+                // this guy is not in our access list.
+llOwnerSay("denying " + llDetectedName(0) + " because not in list and not owner.");
+                return;
+            }
+        }
+        float max_drift = 0.01;
+            // are we considered close enough to home?  not if farther than this amount.
+        vector diff = llGetPos() - home;
+        if (diff.x < 0.0) diff = <diff.x * -1.0, diff.y, diff.z>;
+        if (diff.y < 0.0) diff = <diff.x, diff.y * -1.0, diff.z>;
+        if (diff.z < 0.0) diff = <diff.x, diff.y, diff.z * -1.0>;
+        // this all is not really a vector difference, but more a check on each component.
+        if ( (diff.x > max_drift) || (diff.y > max_drift) || (diff.z > max_drift) ) {
+            // we're far away from home, so let's jump back there.
+            llSetPos(home);
+        } else {
+            // we are at home, so we're jumping away.
+            llSetPos(home - jump_offset);
+            llSetTimerEvent(14.0);  // reset the position in a few secs.
+        }
+    }
+    timer() {
+        llSetPos(home);
+        llSetTimerEvent(0.0);  // reset timer.
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/box_mover_v1.7.txt b/huffware/huffotronic_tools_n_testers_v6.1/box_mover_v1.7.txt
deleted file mode 100755 (executable)
index cd297f2..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-
-// huffware script: box mover, by fred huffhines.
-//
-// a really simple script to make a box jump out of one's way.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-
-//hmmm: fix this to use a notecard for dimensions and members.
-
-
-// modifiable constants.
-
-vector jump_offset = <4.0, -3.0, 0.0>;  // how far to jump away from the starting place.
-
-list allowed_avatars = [ "fred huffhines", "Chronical Koolhoven", "Mojopickle Haystack",
-    "Zeno Olifone", "After9 NightFire", "Wam7c Macchi" ];
-
-// variables below.
-
-vector home;  // where do we live normally?
-
-// makes our list of allowed keys into uniform lower case.
-fix_list_items()
-{
-    integer i;
-    list fixed_list;
-    for (i = 0; i < llGetListLength(allowed_avatars); i++) {
-        string curr = llList2String(allowed_avatars, i);
-        curr = llToLower(curr);
-        fixed_list += [curr];
-    }
-    allowed_avatars = fixed_list;
-//llOwnerSay("got a new list of: " + (string)allowed_avatars);    
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();  // make sure newest addition is only version of script.
-        fix_list_items();  // make sure entries are lower case.
-        home = llGetPos();
-    }
-    
-    touch_start(integer total_number) {
-llOwnerSay("touched by " + llDetectedName(0));
-        // if we're not the owner, then we've got a few extra requirements before
-        // we do anything at all.
-        if (llDetectedKey(0) != llGetOwner()) {
-            list lowname = [ llToLower(llDetectedName(0)) ];
-            if (llListFindList(allowed_avatars, lowname) < 0) {
-                // this guy is not in our access list.
-llOwnerSay("denying " + llDetectedName(0) + " because not in list and not owner.");
-                return;
-            }
-        }
-        float max_drift = 0.01;
-            // are we considered close enough to home?  not if farther than this amount.
-        vector diff = llGetPos() - home;
-        if (diff.x < 0.0) diff = <diff.x * -1.0, diff.y, diff.z>;
-        if (diff.y < 0.0) diff = <diff.x, diff.y * -1.0, diff.z>;
-        if (diff.z < 0.0) diff = <diff.x, diff.y, diff.z * -1.0>;
-        // this all is not really a vector difference, but more a check on each component.
-        if ( (diff.x > max_drift) || (diff.y > max_drift) || (diff.z > max_drift) ) {
-            // we're far away from home, so let's jump back there.
-            llSetPos(home);
-        } else {
-            // we are at home, so we're jumping away.
-            llSetPos(home - jump_offset);
-            llSetTimerEvent(14.0);  // reset the position in a few secs.
-        }
-    }
-    timer() {
-        llSetPos(home);
-        llSetTimerEvent(0.0);  // reset timer.
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/button_pusher_v0.5.lsl b/huffware/huffotronic_tools_n_testers_v6.1/button_pusher_v0.5.lsl
new file mode 100755 (executable)
index 0000000..393918b
--- /dev/null
@@ -0,0 +1,57 @@
+
+// huffware script: button pusher, by fred huffhines
+//
+// a simple API for reporting when buttons are pushed.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// this is a kludgy thing, but this must be hard-coded to have the right button
+// name for what the rest of the device is expecting.  it should vary depending on
+// the actual button prim that this script is placed in.
+string BUTTON_NAME = "next";
+
+// the button pushing API.
+//////////////
+integer BUTTON_PUSHER_HUFFWARE_ID = 10035;
+    // a unique ID within the huffware system for this script.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+string BUTTON_PUSHED_ALERT = "#btnp";
+    // this event is generated when the button is pushed.  the number parameter will be
+    // the huffware id plus the reply distance.  the id parameter in the link message will
+    // contain the name of the button that was pushed.
+//////////////
+
+// generates our button pressed alert, when the user has finished clicking on the button.
+send_button_event()
+{
+//llOwnerSay("user clicked on button " + BUTTON_NAME);
+    llMessageLinked(LINK_SET, BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE,
+        BUTTON_PUSHED_ALERT, BUTTON_NAME);
+}
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+    }
+    
+    touch_end(integer count) {
+        if (llDetectedLinkNumber(0) == llGetLinkNumber())
+            send_button_event();
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/button_pusher_v0.5.txt b/huffware/huffotronic_tools_n_testers_v6.1/button_pusher_v0.5.txt
deleted file mode 100755 (executable)
index 393918b..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-
-// huffware script: button pusher, by fred huffhines
-//
-// a simple API for reporting when buttons are pushed.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// this is a kludgy thing, but this must be hard-coded to have the right button
-// name for what the rest of the device is expecting.  it should vary depending on
-// the actual button prim that this script is placed in.
-string BUTTON_NAME = "next";
-
-// the button pushing API.
-//////////////
-integer BUTTON_PUSHER_HUFFWARE_ID = 10035;
-    // a unique ID within the huffware system for this script.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-string BUTTON_PUSHED_ALERT = "#btnp";
-    // this event is generated when the button is pushed.  the number parameter will be
-    // the huffware id plus the reply distance.  the id parameter in the link message will
-    // contain the name of the button that was pushed.
-//////////////
-
-// generates our button pressed alert, when the user has finished clicking on the button.
-send_button_event()
-{
-//llOwnerSay("user clicked on button " + BUTTON_NAME);
-    llMessageLinked(LINK_SET, BUTTON_PUSHER_HUFFWARE_ID + REPLY_DISTANCE,
-        BUTTON_PUSHED_ALERT, BUTTON_NAME);
-}
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-    }
-    
-    touch_end(integer count) {
-        if (llDetectedLinkNumber(0) == llGetLinkNumber())
-            send_button_event();
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/chaos_picks_a_number_v3.0.lsl b/huffware/huffotronic_tools_n_testers_v6.1/chaos_picks_a_number_v3.0.lsl
new file mode 100755 (executable)
index 0000000..50c0ef1
--- /dev/null
@@ -0,0 +1,263 @@
+
+// huffware script: chaos picks a number, by fred huffhines.
+//     (was formerly called "raffles asks chaos a question")
+//
+// produces a random number between 0 and the MAXIMUM_VALUE defined below.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer MAXIMUM_VALUE = 100;
+    // this is the highest number the generator will produce.
+    // the range is from zero, a very poor pick, to the number above
+    // (the best pick), inclusive.
+
+///////////////
+
+// from hufflets...
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// variables used in the script...
+
+list participants = [];
+    // the people who have already received a number in this drawing.
+
+integer highest_picked = 0;
+    // the highest picked so far.
+
+string winner_so_far = "";
+    // the name of the person who got the highest number to this point.
+
+integer lottery_finished = FALSE;
+    // true when the lottery has been completed.
+
+initialize()
+{
+    highest_picked = 0;
+    participants = [];
+    winner_so_far = "";
+    lottery_finished = FALSE;
+    llSay(0, "ready to draw random numbers from 0 to "
+        + (string)MAXIMUM_VALUE + "...");
+    llListen(0, "", llGetOwner(), "");
+}
+
+// reports the winner, but adds "prefix" to the front of our text and
+// will say 'so far' if "provisional" flag is true.
+call_winner(string prefix, integer provisional)
+{
+    string disclaimer = "";  // extra text if not final result.
+    if (provisional) disclaimer = "so far ";
+    string winner = winner_so_far;
+    if (!llStringLength(winner)) winner = "no one(!)";
+    llSay(0, prefix + "winner " + disclaimer + "is " + winner
+        + " who picked " + (string)highest_picked + ".");
+}
+
+announce_final_winner()
+{
+    call_winner("The **final** ", FALSE);
+}
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        initialize();
+    }
+    
+    on_rez(integer param) { llResetScript(); }
+
+    touch_start(integer total_number)
+    {
+        integer which_picker;
+        for (which_picker = 0; which_picker < total_number; which_picker++) {
+            if (llDetectedKey(which_picker) == llGetOwner()) {
+                llOwnerSay("as owner you can say\n'#winner' to hear the current winner,\n'#final' to close the drawing and,\n'#reset lottery' to start a new drawing.");
+                call_winner("the ", TRUE);
+                return;
+            }
+            
+            if (lottery_finished) {
+                // just report that this one's finished.
+                announce_final_winner();
+                return;
+            }
+            
+            // if we got to here, this is a normal person (not the owner) who
+            // might still be allowed to participate in an active drawing.
+            
+            // get a random number between 0 and almost up to the max.
+            float rando = llFrand(MAXIMUM_VALUE);
+            // convert to int, which makes the range from zero to the max inclusive.
+            integer int_rando = llRound(rando);
+            string letter = "";  // default is no extra letter.
+            // pick the right article for english.
+            if ( (int_rando == 8)
+                || (int_rando == 11)
+                || (int_rando == 18)
+                || (int_rando / 10 == 8) ) {
+                // these cases like an "an" instead of an "a".
+                // e.g., an eleven, an eight, an eighty-three, an eighteen.
+                letter = "n";
+            }
+
+            // make sure this person hasn't already played.
+            string name = llDetectedName(which_picker);
+            if (find_in_list(participants, name) >= 0) {
+                call_winner(name + " already picked a number,\nand the ", TRUE);
+                return;
+            }
+
+            // add the new participant to the list.
+            participants += [ name ];
+                // list kludge for better memory usage.
+            llSay(0, name + " drew a" + letter + " " + (string)int_rando + ".");
+            if (highest_picked < int_rando) {
+                llSay(0, name + " has the new highest number!!!");
+                highest_picked = int_rando;
+                winner_so_far = name;
+            } else if (highest_picked == int_rando) {
+                call_winner("oh, so close; " + name + " tied with the ", FALSE);
+            } else {
+                call_winner("that's not quite enough " + name + ", since\nthe ", TRUE);
+            }
+        }
+    }
+    
+    listen(integer channel, string name, key id, string msg) {
+        if (msg == "#reset lottery") {
+            llSay(0, "resetting the drawing now...");
+            if (winner_so_far != "")
+                call_winner("forgetting previous ", FALSE);
+            initialize();
+        } else if (msg == "#winner") {
+            call_winner("the ", TRUE);
+        } else if (msg == "#final") {
+            lottery_finished = TRUE;
+            announce_final_winner();
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/chaos_picks_a_number_v3.0.txt b/huffware/huffotronic_tools_n_testers_v6.1/chaos_picks_a_number_v3.0.txt
deleted file mode 100755 (executable)
index 50c0ef1..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-
-// huffware script: chaos picks a number, by fred huffhines.
-//     (was formerly called "raffles asks chaos a question")
-//
-// produces a random number between 0 and the MAXIMUM_VALUE defined below.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer MAXIMUM_VALUE = 100;
-    // this is the highest number the generator will produce.
-    // the range is from zero, a very poor pick, to the number above
-    // (the best pick), inclusive.
-
-///////////////
-
-// from hufflets...
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// variables used in the script...
-
-list participants = [];
-    // the people who have already received a number in this drawing.
-
-integer highest_picked = 0;
-    // the highest picked so far.
-
-string winner_so_far = "";
-    // the name of the person who got the highest number to this point.
-
-integer lottery_finished = FALSE;
-    // true when the lottery has been completed.
-
-initialize()
-{
-    highest_picked = 0;
-    participants = [];
-    winner_so_far = "";
-    lottery_finished = FALSE;
-    llSay(0, "ready to draw random numbers from 0 to "
-        + (string)MAXIMUM_VALUE + "...");
-    llListen(0, "", llGetOwner(), "");
-}
-
-// reports the winner, but adds "prefix" to the front of our text and
-// will say 'so far' if "provisional" flag is true.
-call_winner(string prefix, integer provisional)
-{
-    string disclaimer = "";  // extra text if not final result.
-    if (provisional) disclaimer = "so far ";
-    string winner = winner_so_far;
-    if (!llStringLength(winner)) winner = "no one(!)";
-    llSay(0, prefix + "winner " + disclaimer + "is " + winner
-        + " who picked " + (string)highest_picked + ".");
-}
-
-announce_final_winner()
-{
-    call_winner("The **final** ", FALSE);
-}
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        initialize();
-    }
-    
-    on_rez(integer param) { llResetScript(); }
-
-    touch_start(integer total_number)
-    {
-        integer which_picker;
-        for (which_picker = 0; which_picker < total_number; which_picker++) {
-            if (llDetectedKey(which_picker) == llGetOwner()) {
-                llOwnerSay("as owner you can say\n'#winner' to hear the current winner,\n'#final' to close the drawing and,\n'#reset lottery' to start a new drawing.");
-                call_winner("the ", TRUE);
-                return;
-            }
-            
-            if (lottery_finished) {
-                // just report that this one's finished.
-                announce_final_winner();
-                return;
-            }
-            
-            // if we got to here, this is a normal person (not the owner) who
-            // might still be allowed to participate in an active drawing.
-            
-            // get a random number between 0 and almost up to the max.
-            float rando = llFrand(MAXIMUM_VALUE);
-            // convert to int, which makes the range from zero to the max inclusive.
-            integer int_rando = llRound(rando);
-            string letter = "";  // default is no extra letter.
-            // pick the right article for english.
-            if ( (int_rando == 8)
-                || (int_rando == 11)
-                || (int_rando == 18)
-                || (int_rando / 10 == 8) ) {
-                // these cases like an "an" instead of an "a".
-                // e.g., an eleven, an eight, an eighty-three, an eighteen.
-                letter = "n";
-            }
-
-            // make sure this person hasn't already played.
-            string name = llDetectedName(which_picker);
-            if (find_in_list(participants, name) >= 0) {
-                call_winner(name + " already picked a number,\nand the ", TRUE);
-                return;
-            }
-
-            // add the new participant to the list.
-            participants += [ name ];
-                // list kludge for better memory usage.
-            llSay(0, name + " drew a" + letter + " " + (string)int_rando + ".");
-            if (highest_picked < int_rando) {
-                llSay(0, name + " has the new highest number!!!");
-                highest_picked = int_rando;
-                winner_so_far = name;
-            } else if (highest_picked == int_rando) {
-                call_winner("oh, so close; " + name + " tied with the ", FALSE);
-            } else {
-                call_winner("that's not quite enough " + name + ", since\nthe ", TRUE);
-            }
-        }
-    }
-    
-    listen(integer channel, string name, key id, string msg) {
-        if (msg == "#reset lottery") {
-            llSay(0, "resetting the drawing now...");
-            if (winner_so_far != "")
-                call_winner("forgetting previous ", FALSE);
-            initialize();
-        } else if (msg == "#winner") {
-            call_winner("the ", TRUE);
-        } else if (msg == "#final") {
-            lottery_finished = TRUE;
-            announce_final_winner();
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/collider_v1.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/collider_v1.3.lsl
new file mode 100755 (executable)
index 0000000..e513fc1
--- /dev/null
@@ -0,0 +1,150 @@
+
+// huffware script: collider, by fred huffhines
+//
+// a simple script that plays sounds in the inventory when a collision occurs.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+float SOUND_VOLUME = 0.3;
+    // how loudly to play the sounds we find.
+
+integer TIME_BETWEEN_PLAYS = 3;
+    // we only make the sound every X seconds.
+
+integer last_played = 0;
+    // records the last time we hit the sound.
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+
+        integer i;
+        for (i = 0; i < llGetInventoryNumber(INVENTORY_SOUND); i++)
+            llPreloadSound(llGetInventoryName(INVENTORY_SOUND, i));
+    }
+
+    collision_start(integer total_number) {
+        if (llGetUnixTime() - last_played < TIME_BETWEEN_PLAYS) return;
+        last_played = llGetUnixTime();
+        integer i;
+        for (i = 0; i < llGetInventoryNumber(INVENTORY_SOUND); i++) {
+            float vol = SOUND_VOLUME;
+            if (llGetInventoryName(INVENTORY_SOUND, i) == "water-flowing3")
+                vol /= 2.0;  // not so loud for this one.
+            llTriggerSound(llGetInventoryName(INVENTORY_SOUND, i), vol);
+//llSay(0, "vol is " + (string)vol);
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/collider_v1.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/collider_v1.3.txt
deleted file mode 100755 (executable)
index e513fc1..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-
-// huffware script: collider, by fred huffhines
-//
-// a simple script that plays sounds in the inventory when a collision occurs.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-float SOUND_VOLUME = 0.3;
-    // how loudly to play the sounds we find.
-
-integer TIME_BETWEEN_PLAYS = 3;
-    // we only make the sound every X seconds.
-
-integer last_played = 0;
-    // records the last time we hit the sound.
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-
-        integer i;
-        for (i = 0; i < llGetInventoryNumber(INVENTORY_SOUND); i++)
-            llPreloadSound(llGetInventoryName(INVENTORY_SOUND, i));
-    }
-
-    collision_start(integer total_number) {
-        if (llGetUnixTime() - last_played < TIME_BETWEEN_PLAYS) return;
-        last_played = llGetUnixTime();
-        integer i;
-        for (i = 0; i < llGetInventoryNumber(INVENTORY_SOUND); i++) {
-            float vol = SOUND_VOLUME;
-            if (llGetInventoryName(INVENTORY_SOUND, i) == "water-flowing3")
-                vol /= 2.0;  // not so loud for this one.
-            llTriggerSound(llGetInventoryName(INVENTORY_SOUND, i), vol);
-//llSay(0, "vol is " + (string)vol);
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/comfortable_sitting_v7.5.lsl b/huffware/huffotronic_tools_n_testers_v6.1/comfortable_sitting_v7.5.lsl
new file mode 100755 (executable)
index 0000000..202c58f
--- /dev/null
@@ -0,0 +1,882 @@
+
+// huffware script: comfortable sitting, by fred huffhines.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+
+// global constants...
+
+string NOTEWORTHY_SIGNATURE = "#sitting";
+    // the notecard must begin with this as its first line for it to be
+    // recognized as our configuration card.
+
+//////////////
+
+// global variables that are loaded from a notecard.
+
+vector AVATAR_ROTATION = <0, 0, -90>;  // star chair.
+//vector AVATAR_ROTATION = <0, 0, 0>;
+    // the euler vector for rotation of the avatar after sitting, in degrees.
+    // the rotation vector should be tailored to the object.
+
+vector AVATAR_POSITION = <-0.1, -0.28, -0.1>;  // star chair.
+//vector AVATAR_POSITION = <0.34, 0, 0>;
+    // the position of the sitting offset from the object center.   also needs to be
+    // tailored to the particular object.
+
+integer GOTO_WHICH_FLOOR = 1;
+    // when serving as an elevator, this is a way to cause the teleport offset
+    // to go to a particular floor.  the real z position is calculated from
+    // this times the floor size in meters.  note that floors are numbered
+    // starting at 1 (one).
+    
+float FLOOR_SIZE_IN_METERS = 0.0;
+    // when the script is used in an elevator, this specifies the height of the
+    // floors.  our current scheme will only work if that is constant between
+    // the floors.
+
+float BASE_FLOOR_HEIGHT = 0.0;
+    // the position of the first floor in meters.  this will not affect the
+    // position calculations unless floor size is non-zero.
+
+integer UNSEAT_AFTERWARDS = FALSE;
+    // if this is true, then the avatar is unseated just after sitting down.
+    
+float PAUSE_BEFORE_EVICTION = 0.28;
+    // the number of seconds that the avatars get to sit before we pop them
+    // out of the chair/teleporter/whatever.
+
+vector CAMERA_EYE_OFFSET = <3, 2, 1.5>;  // star chair.
+    // the offset for the camera after the avatar sits down.
+//relative to the avatar?
+
+vector CAMERA_TARGET = <-3, 0, 1>;  // star chair.
+    // the location where the camera is looking at once the avatar sits down.
+//relative to the avatar?
+
+//////////////
+
+// global variables used in processing notecards...
+
+integer pending_response_id;  // set to uniquely identify the notecard read in progress.
+list global_config_list;  // a collection of configuration parameters from our notecard.
+integer global_config_index;  // allows wrap-around feature, which we don't use here.
+
+//////////////
+
+// interfaces for library scripts we rely on...
+
+// requires noteworthy library.
+// in this odd case, where we are trying to shrink script count, the noteworthy library
+// is embedded inside here.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be blank.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
+    // found) and as subsequent elements an embedded list that was read from the
+    // notecard.  this necessarily limits the size of the notecards that we can read
+    // and return.
+string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
+    // like the read notecard command, but specifies the notecard name to use.  only that
+    // specific notecard file will be consulted.  first and second parm are still signature
+    // and response code, third parm is the notecard name.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// establishes the sitting parameters including camera offsets.
+setup_seating_arrangements()
+{
+    llUnSit(llAvatarOnSitTarget());  // no one gets to ignore a script change.        
+    vector new_rot = AVATAR_ROTATION;
+    new_rot *= DEG_TO_RAD;  // convert to radians.
+    rotation quat = llEuler2Rot(new_rot);  // convert to quaternion.
+    // get our position set up and take into account the elevator position.
+    vector position = AVATAR_POSITION;
+//rename that variable to be "which floor to go to"
+    if (FLOOR_SIZE_IN_METERS != 0) {
+        vector temp = llGetPos();
+        integer my_floor = (integer) ((temp.z - BASE_FLOOR_HEIGHT ) / FLOOR_SIZE_IN_METERS) + 1;
+//log_it("my floor is " + (string)my_floor);
+        float add_in = (float)(GOTO_WHICH_FLOOR - my_floor) * FLOOR_SIZE_IN_METERS;
+//log_it("decided to add in z: " + (string)add_in);
+        position += <0, 0, add_in>;        
+    }
+    // also we make this absolute by taking out the object's own rotation.
+    // it's hard enough in life for z components to not mean z axis.
+    position /= llGetRot();
+    llSitTarget(position, quat / llGetRot());
+//hmmm: do we need same rot treatment on camera things?    
+//hmmm: trying it.
+    // now set the camera position to avoid having random viewpoint.
+    llSetCameraEyeOffset(CAMERA_EYE_OFFSET / llGetRot());
+    llSetCameraAtOffset(CAMERA_TARGET / llGetRot());
+}
+
+// this function fires off a request to the noteworthy library via a link message.
+// noteworthy will look for a notecard with our particular signature in it and
+// if it finds one, it will read the configuration therein.  an empty string is
+// returned if noteworthy couldn't find anything.
+request_configuration()
+{
+    // try to find a notecard with our configuration.
+    pending_response_id = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([NOTEWORTHY_SIGNATURE, pending_response_id]);
+//call direct into noteworthy.
+noteworthy_handle_link_message(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND, parms_sent);
+        
+//    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+//         parms_sent);
+}
+
+// processes link messages received from the noteworthy library.
+handle_link_message(integer which, integer num, string msg, key id)
+{
+    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
+            || (msg != READ_NOTECARD_COMMAND) )
+        return;  // not for us.
+//log_it("handl: msg=" + msg + " id=" + id);
+    // process the result of reading the notecard.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string notecard_name = llList2String(parms, 0);
+//log_it("raw is " + llList2String(parms, 1));
+    integer response_for = llList2Integer(parms, 1);
+//log_it("resp cod=" + pending_response_id + " but this for=" + response_for);
+//if (response_for != pending_response_id) log_it("bad response code???");    
+    if (response_for != pending_response_id) return;  // oops, this isn't for us.
+    if (notecard_name == BAD_NOTECARD_INDICATOR) {
+        // we hated the notecards we found, or there were none.
+        log_it("We apologize; there seem to be no notecards with a first line of '"
+            + NOTEWORTHY_SIGNATURE
+            + "'.  We can't read any configuration until that situation improves.");
+    } else {
+//log_it("got to handle link");
+        // snag all but the first two elements for our config now.
+        global_config_list += llList2List(parms, 2, -1);
+        // make sure we shouldn't keep going.
+        if (notecard_name != NOTECARD_READ_CONTINUATION) {
+            // a valid notecard has been found.
+            global_config_index = 0;  // we are starting over in the config list.
+//            log_it("read notecard \"" + notecard_name + "\":");
+            // and process the file as a set of definitions.
+            process_ini_config();
+            // now that we have a new set of parameters, use them.
+            setup_seating_arrangements();
+        }
+    }
+}
+
+///////////////
+
+// consumes the notecard in a very application specific way to retrieve our configuration items.
+// the example script only looks for two variables: name and description.  if those are found in
+// the sample card, then they are proudly shown.
+parse_variable_definition(string to_parse)
+{
+    string content;  // filled after finding a variable name.
+    if ( (content = get_variable_value(to_parse, "avatar_rotation")) != "") {
+        AVATAR_ROTATION = (vector)content;
+//        log_it("** got avatar_rotation of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "avatar_position")) != "") {
+        AVATAR_POSITION = (vector)content;
+//        log_it("** got avatar_position of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "goto_which_floor")) != "") {
+        GOTO_WHICH_FLOOR = (integer)content;
+//        log_it("** got GOTO_WHICH_FLOOR of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "floor_size_in_meters")) != "") {
+        FLOOR_SIZE_IN_METERS = (float)content;
+//        log_it("** got FLOOR_SIZE_IN_METERS of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "base_floor_height")) != "") {
+        BASE_FLOOR_HEIGHT = (float)content;
+//        log_it("** got BASE_FLOOR_HEIGHT of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "unseat_afterwards")) != "") {
+        UNSEAT_AFTERWARDS = (integer)content;
+//        log_it("** got unseat_afterwards of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "pause_before_eviction")) != "") {
+        PAUSE_BEFORE_EVICTION = (float)content;
+//        log_it("** got pause_before_eviction of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "camera_eye_offset")) != "") {
+        CAMERA_EYE_OFFSET = (vector)content;
+//        log_it("** got camera_eye_offset of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "camera_target")) != "") {
+        CAMERA_TARGET = (vector)content;
+//        log_it("** got camera_target of '" + content + "'");
+//    } else {
+//        log_it("unknown variable seen: " + to_parse);
+    }
+}
+
+initialize()
+{
+    // reset our relevant variables.
+    global_config_list = [];
+    global_config_index = 0;
+
+    // announce that we're open for business.
+///    log_it("started, free mem=" + (string)llGetFreeMemory());
+
+    // request that the noteworthy library start looking for our notecard.
+    request_configuration();
+    
+    integer indy = 32;
+    while (indy >= 0) {
+        indy = find_in_inventory_partial("noteworthy", INVENTORY_SCRIPT);
+        if (indy >= 0) {
+            llRemoveInventory(llGetInventoryName(INVENTORY_SCRIPT, indy));
+        }
+    }
+    
+}
+
+//////////////
+// from hufflets...
+//
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// strips the spaces off of the beginning and end of a string.
+string strip_spaces(string to_strip)
+{
+    // clean out initial spaces.
+    while (llGetSubString(to_strip, 0, 0) == " ")
+        to_strip = llDeleteSubString(to_strip, 0, 0);
+    // clean out ending spaces.
+    while (llGetSubString(to_strip, -1, -1) == " ")
+        to_strip = llDeleteSubString(to_strip, -1, -1);
+    return to_strip;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+    return [ strip_spaces(x), strip_spaces(y) ];
+}
+
+// returns a non-empty string if "to_check" defines a value for "variable_name".
+// this must be in the form "X=Y", where X is the variable_name and Y is the value.
+string get_variable_value(string to_check, string variable_name)
+{
+    list x_y = separate_variable_definition(to_check);
+    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
+    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
+    return llList2String(x_y, 1);  // a match!
+}
+
+// examines all entries that we got from the notecard to see if any contain definitions.
+// this is basically an INI file reader, but it uses a list instead of a file.
+// ini files provide a format with multiple sections of config information, like so:
+//    [section_1]
+//    name1=value1
+//    name2=value2 ...etc...
+//    [section_2]
+//    name1=value1 ...etc...
+process_ini_config()
+{
+//    log_it("scanning notecard for variable definitions...");
+    integer indy;
+    integer count = llGetListLength(global_config_list);
+    string section_name;  // set later if we see one.
+
+    // iterate across the items in our configuration to look for ones that are not done yet.            
+    for (indy = global_config_index; indy < count; indy++) {
+        string line = llList2String(global_config_list, indy);
+        // search for a section beginning.
+        if (llGetSubString(line, 0, 0) == "[") {
+            // we found the start of a section name.  now read the contents.
+            indy++;  // skip section line.
+            section_name = llGetSubString(line, 1, -2);
+            log_it("reading section: " + section_name);
+        }
+        integer sec_indy;
+        for (sec_indy = indy; sec_indy < count; sec_indy++) {
+            // read the lines in the section.
+            line = llList2String(global_config_list, sec_indy);
+            if (llGetSubString(line, 0, 0) != "[") {
+                // try to interpret this line as a variable setting.  this is just
+                // one example of a way to handle the config file; one might instead
+                // want to do something below once a whole section is read.
+                parse_variable_definition(line);
+                indy = sec_indy;  // track that we've passed this line.
+            } else {
+                // we're at the beginning of a new section now, so start processing its
+                // configuration in the outer loop.
+                indy = sec_indy - 1;  // set indy to proper beginning of section.
+                global_config_index = indy;  // remember where we had read to.
+                sec_indy = count + 3;  // skip remainder of inner loop.
+            }
+        }
+    }
+
+    global_config_index = 0;  // reset outer position if want to re-read.
+}
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory_partial(string name_to_find, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 1.9.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+//
+// example usage of the auto-retirement script:
+//
+// default {
+//    state_entry() {
+//        auto_retire();  // make sure newest addition is only version of script.
+//    }
+// }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                if ((float)inv_version_string < (float)version_string) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
+        
+    string basename = to_chop_up;  // script name with no version attached.
+    
+    integer posn;
+    // minimum script name is 2 characters plus version.
+    for (posn = llStringLength(to_chop_up) - 1;
+        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
+        posn--) {
+        // find the space.  do nothing else.
+    }
+    if (posn < 2) return [];  // no space found.
+    string full_suffix = llGetSubString(to_chop_up, posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets
+//////////////
+
+//////////////
+// from noteworthy:
+
+// huffware script: noteworthy library, by fred huffhines.
+//
+// a handy approach to reading a notecard.  this version supports requiring
+// a 'signature' in the notecard's first line, so that multiple notecards can
+// exist in an object without being misinterpreted.  the script is accessed via
+// its link message API, so it can be used in an object without all this code
+// needing to be embedded in another script.  it also supports queuing up requests
+// to read notecards, so multiple scripts can use it to read their specific
+// notecards without any special handling (besides waiting a bit longer).
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants that can be adapted to your needs...
+
+integer DEBUGGING = FALSE;
+    // if this is true, then a lot of extra noise is generated when notecards are read.
+
+float TIME_OUT_ON_ONE_NOTECARD = 120.0;
+    // we allow one line of a notecard this long to be read before we decide it's hosed.
+    // some sims are very very slow, and a time-out of one minute has been found lacking;
+    // we saw at least one case where the first notecard line to be read took longer than
+    // 60 seconds.  that's why we keep cranking this time-out up...
+
+// constants that should not be changed...
+
+// outcomes from handling a line in a notecard.
+integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
+integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
+integer DONE_READING = -10;  // the notecard is finished being read.
+
+integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
+
+integer MAXIMUM_LINES_USED = 4;
+    // we will read this many lines at a time from the appropriate notecard.
+// global variables...
+
+string requested_signature = "";
+    // if this is non-empty, then it must be found in the first line of the script.
+
+integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
+
+string global_notecard_name;  // the name of the card we're reading now.
+key global_query_id = NULL_KEY;  // the identifier of our data query.
+integer current_response_code = 0;  // the code that our client uses for its reading.
+list global_query_contents;  // the lines we have read from the notecard.
+
+integer line_number = 0;  // which line are we at in notecard?
+
+integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
+
+integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
+
+list pending_signatures;  // signatures from queued requests for reading.
+list pending_response_codes;  // response codes for the queued requests.
+list pending_notecard_names;  // card names if it's a specific request.
+
+//////////////
+
+startup_initialize()
+{
+    llSetTimerEvent(0.0);
+    pending_signatures = [];
+    pending_response_codes = [];
+    pending_notecard_names = [];
+    current_response_code = 0;
+}
+
+reset_for_reading(string signature, integer response_code_in)
+{
+    requested_signature = signature;
+    current_response_code = response_code_in;
+    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
+    global_query_contents = [];
+    global_notecard_name = "";
+    line_number = 0;
+    found_signature_line = FALSE;
+    trying_notecard_at = -1;
+    global_query_id = NULL_KEY;
+}
+
+// use the existing global notecard setting to start reading.
+select_specific_notecard()
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    line_number = 0;  // reset line number again.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// picks the notecard at the "index" (from 0 to num_notecards - 1) and
+// starts reading it.
+select_notecard(integer index)
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
+    if (card_specified == "") return;   // not good.  bad index.
+    global_notecard_name = card_specified;
+    line_number = 0;  // reset line number again.
+    // we have a new file name, so load up the destinations, hopefully.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// increments our index in the count of notecards that the object has, and start
+// reading the next notecard (at the index).
+integer try_next_notecard()
+{
+    if (only_read_one_notecard) {
+        return FALSE;  // we were only going to try one.
+    }
+    // reset some values that might have applied before.
+    global_notecard_name = "";
+    // skip to the next card.
+    trying_notecard_at++;
+    // make sure we're not over the count of cards.
+    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
+        // this is a problem.  we didn't find anything suitable.
+        return FALSE;
+    }
+    // so, now we'll try the next notecard to look for our signature.
+    select_notecard(trying_notecard_at);
+    return TRUE;
+}
+
+// process a line of text that we received from the current notecard.
+integer handle_notecard_line(key query_id, string data)
+{
+    // if we're not at the end of the notecard we're reading...
+    if (data != EOF) {
+        // there's more to read in the notecard still.
+        if (data != "") {
+            // make sure we even have a signature to look for.
+            if (!found_signature_line && (requested_signature == "")) {
+                // no signature means that we always find it.
+                found_signature_line = TRUE;
+            }
+            // did we already get our signature?  if not, see if this is it.
+            if (!found_signature_line && (data != requested_signature) ) {
+                // this is a bad notecard.  skip it.
+                if (!try_next_notecard()) {
+                    // we have no more to work with.
+                    return BAD_NOTECARD;
+                }
+                return STILL_READING;  // we'll keep going.
+            } else if (!found_signature_line && (data == requested_signature) ) {
+                // this is a good signature line, so record that and then skip it.
+                found_signature_line = TRUE;
+            } else {
+                if (DEBUGGING
+                    && ( ( (requested_signature == "") && (line_number == 0) )
+                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
+                    log_it("started reading " + global_notecard_name + "...");
+                }
+                // don't record any lines that are comments.
+                if ( (llGetSubString(data, 0, 0) != "#")
+                    && (llGetSubString(data, 0, 0) != ";") ) {
+                    // add the non-blank line to our list.
+                    global_query_contents += data;
+                    // make sure we still have enough space to keep going.
+                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
+                        // ooh, make sure we pause before blowing our heap&stack.
+                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
+                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
+                    }
+                }
+            }
+        }
+        line_number++;  // increase the line count.
+        // reset the timer rather than timing out, if we actually got some data.
+        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
+        // request the next line from the notecard.
+        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
+        if (global_query_id == NULL_KEY) {
+//log_it("failed to restart notecard reading.");
+            return DONE_READING;
+//is that the best outcome?
+        }
+        return STILL_READING;
+    } else {
+        // that's the end of the notecard.  we need some minimal verification that it
+        // wasn't full of garbage.
+        if (!found_signature_line) {
+            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
+            if (!try_next_notecard()) {
+                return BAD_NOTECARD;  // we failed to find a good line?
+            } else {
+                // the next notecard's coming through now.
+                return STILL_READING;
+            }
+        } else {
+//            if (DEBUGGING) log_it("found signature.");
+            // saw the signature line, so this is a good one.
+            return DONE_READING;
+        }
+    }
+}
+
+// only sends reply; does not reset notecard process.
+send_reply(integer destination, list parms, string command,
+    integer include_query)
+{
+//log_it("froyo: curre code=" + current_response_code);
+//integer items = llGetListLength(parms);
+//if (include_query) items += llGetListLength(global_query_contents);
+//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
+
+   if (!include_query) {
+        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+    } else {
+        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command,
+            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
+    }
+    global_query_contents = [];
+//log_it("post-sending, mem=" + (string)llGetFreeMemory());
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply_and_reset(integer destination, list parms, string command,
+    integer include_query)
+{
+    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
+    send_reply(destination, parms, command, include_query);
+//log_it("about to reset response code");
+    current_response_code = 0;  // reset back to default so we can start another read.
+    global_query_id = NULL_KEY;  // reset so we accept no more data.
+}
+
+// if there are other pending notecard reads, this goes to the next one listed.
+dequeue_next_request()
+{
+    if (llGetListLength(pending_signatures)) {
+        // get the info from the next pending item.
+        string sig = llList2String(pending_signatures, 0);
+        integer response_code_temp = llList2Integer(pending_response_codes, 0);
+        string notecard = llList2String(pending_notecard_names, 0);
+        // whack the head of the queue since we grabbed the info.
+        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
+        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
+        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
+        if (llStringLength(notecard)) {
+            global_notecard_name = notecard;
+            select_specific_notecard();
+        } else {
+            reset_for_reading(sig, response_code_temp);
+        }
+    }
+}
+
+// deals with one data server answer from the notecard.
+process_notecard_line(key query_id, string data)
+{
+    // try to consume a line from the notecard.
+    integer outcome = handle_notecard_line(query_id, data);
+    if (outcome == DONE_READING) {
+        // that was a valid notecard and we read all of it.
+        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
+        // send back the results.
+        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
+            READ_NOTECARD_COMMAND, TRUE);
+    } else if (outcome == BAD_NOTECARD) {
+        // bail; this problem must be addressed by other means.
+        if (DEBUGGING) log_it("failed to find an appropriate notecard");
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    } else if (outcome == STILL_READING) {
+        // we have a good card and are still processing it.
+        return;
+    } else {
+        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
+        // again, bail out.  we have no idea what happened with this.
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    }
+    // if we have reached here, we should crank up the next queued notecard reading.
+    dequeue_next_request();
+}
+
+// processes requests from our users.
+noteworthy_handle_link_message(integer which, integer num, string msg, key id)
+{
+    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
+
+    if (msg == READ_NOTECARD_COMMAND) {
+        only_read_one_notecard = FALSE;  // general inquiry for any card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read notecard--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code_temp = llList2Integer(parms, 1);
+//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code_temp);
+            if (!try_next_notecard()) {
+                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
+                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code_temp ],
+                    READ_NOTECARD_COMMAND, FALSE);
+                return;
+            }
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code_temp;
+//holding:            pending_notecard_names += "";
+//holding:        }
+    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
+        only_read_one_notecard = TRUE;  // they want one particular card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read specific--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code_temp = llList2Integer(parms, 1);
+        string notecard_name = llList2String(parms, 2);
+//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code_temp);
+            global_notecard_name = notecard_name;  // set our global.
+            select_specific_notecard();
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code_temp;
+//holding:            pending_notecard_names += notecard_name;
+//holding:        }
+    }
+}
+
+    
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();  // make sure newest addition is only version of script.
+/////not needed now        llSleep(1.0);  // snooze just a bit to let noteworthy start up?
+        startup_initialize();
+        initialize();  // start asking about the notecards.
+        setup_seating_arrangements();  // use our current defaults for sitting posn.
+    }
+
+    on_rez(integer parm) { llResetScript(); }
+
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+//            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
+            llResetScript(); 
+        }
+        if (!(change & CHANGED_LINK)) return;  // don't care.
+        if (!UNSEAT_AFTERWARDS) return;  // nothing else below is needed.
+        if (llAvatarOnSitTarget() == NULL_KEY) return;  // no one there, so ditto.
+        // now give them a bit of time to rest before dumping them.
+        llSetTimerEvent(PAUSE_BEFORE_EVICTION);
+    }
+    
+    timer() {
+        if (current_response_code != 0) {
+            llSetTimerEvent(0.0);  // stop any timer now.
+            // let the caller know this has failed out.
+            if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
+            send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+                READ_NOTECARD_COMMAND, FALSE);
+            current_response_code = 0;  // we gave up on that one.
+            dequeue_next_request();  // get next reading started if we have anything to read.
+        } else {
+            // perform short range teleport, effectively...
+            llUnSit(llAvatarOnSitTarget());  // ha, got that guy back up.
+            llSetTimerEvent(0.0);  // reset timer.
+        }
+    }
+
+    // process the response from the noteworthy library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+
+    dataserver(key query_id, string data) {
+        // make sure this data is for us.
+        if (global_query_id != query_id) return;
+        // yep, seems to be.
+        process_notecard_line(query_id, data);
+    }            
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/comfortable_sitting_v7.5.txt b/huffware/huffotronic_tools_n_testers_v6.1/comfortable_sitting_v7.5.txt
deleted file mode 100755 (executable)
index 202c58f..0000000
+++ /dev/null
@@ -1,882 +0,0 @@
-
-// huffware script: comfortable sitting, by fred huffhines.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-
-// global constants...
-
-string NOTEWORTHY_SIGNATURE = "#sitting";
-    // the notecard must begin with this as its first line for it to be
-    // recognized as our configuration card.
-
-//////////////
-
-// global variables that are loaded from a notecard.
-
-vector AVATAR_ROTATION = <0, 0, -90>;  // star chair.
-//vector AVATAR_ROTATION = <0, 0, 0>;
-    // the euler vector for rotation of the avatar after sitting, in degrees.
-    // the rotation vector should be tailored to the object.
-
-vector AVATAR_POSITION = <-0.1, -0.28, -0.1>;  // star chair.
-//vector AVATAR_POSITION = <0.34, 0, 0>;
-    // the position of the sitting offset from the object center.   also needs to be
-    // tailored to the particular object.
-
-integer GOTO_WHICH_FLOOR = 1;
-    // when serving as an elevator, this is a way to cause the teleport offset
-    // to go to a particular floor.  the real z position is calculated from
-    // this times the floor size in meters.  note that floors are numbered
-    // starting at 1 (one).
-    
-float FLOOR_SIZE_IN_METERS = 0.0;
-    // when the script is used in an elevator, this specifies the height of the
-    // floors.  our current scheme will only work if that is constant between
-    // the floors.
-
-float BASE_FLOOR_HEIGHT = 0.0;
-    // the position of the first floor in meters.  this will not affect the
-    // position calculations unless floor size is non-zero.
-
-integer UNSEAT_AFTERWARDS = FALSE;
-    // if this is true, then the avatar is unseated just after sitting down.
-    
-float PAUSE_BEFORE_EVICTION = 0.28;
-    // the number of seconds that the avatars get to sit before we pop them
-    // out of the chair/teleporter/whatever.
-
-vector CAMERA_EYE_OFFSET = <3, 2, 1.5>;  // star chair.
-    // the offset for the camera after the avatar sits down.
-//relative to the avatar?
-
-vector CAMERA_TARGET = <-3, 0, 1>;  // star chair.
-    // the location where the camera is looking at once the avatar sits down.
-//relative to the avatar?
-
-//////////////
-
-// global variables used in processing notecards...
-
-integer pending_response_id;  // set to uniquely identify the notecard read in progress.
-list global_config_list;  // a collection of configuration parameters from our notecard.
-integer global_config_index;  // allows wrap-around feature, which we don't use here.
-
-//////////////
-
-// interfaces for library scripts we rely on...
-
-// requires noteworthy library.
-// in this odd case, where we are trying to shrink script count, the noteworthy library
-// is embedded inside here.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be blank.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
-    // found) and as subsequent elements an embedded list that was read from the
-    // notecard.  this necessarily limits the size of the notecards that we can read
-    // and return.
-string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
-    // like the read notecard command, but specifies the notecard name to use.  only that
-    // specific notecard file will be consulted.  first and second parm are still signature
-    // and response code, third parm is the notecard name.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// establishes the sitting parameters including camera offsets.
-setup_seating_arrangements()
-{
-    llUnSit(llAvatarOnSitTarget());  // no one gets to ignore a script change.        
-    vector new_rot = AVATAR_ROTATION;
-    new_rot *= DEG_TO_RAD;  // convert to radians.
-    rotation quat = llEuler2Rot(new_rot);  // convert to quaternion.
-    // get our position set up and take into account the elevator position.
-    vector position = AVATAR_POSITION;
-//rename that variable to be "which floor to go to"
-    if (FLOOR_SIZE_IN_METERS != 0) {
-        vector temp = llGetPos();
-        integer my_floor = (integer) ((temp.z - BASE_FLOOR_HEIGHT ) / FLOOR_SIZE_IN_METERS) + 1;
-//log_it("my floor is " + (string)my_floor);
-        float add_in = (float)(GOTO_WHICH_FLOOR - my_floor) * FLOOR_SIZE_IN_METERS;
-//log_it("decided to add in z: " + (string)add_in);
-        position += <0, 0, add_in>;        
-    }
-    // also we make this absolute by taking out the object's own rotation.
-    // it's hard enough in life for z components to not mean z axis.
-    position /= llGetRot();
-    llSitTarget(position, quat / llGetRot());
-//hmmm: do we need same rot treatment on camera things?    
-//hmmm: trying it.
-    // now set the camera position to avoid having random viewpoint.
-    llSetCameraEyeOffset(CAMERA_EYE_OFFSET / llGetRot());
-    llSetCameraAtOffset(CAMERA_TARGET / llGetRot());
-}
-
-// this function fires off a request to the noteworthy library via a link message.
-// noteworthy will look for a notecard with our particular signature in it and
-// if it finds one, it will read the configuration therein.  an empty string is
-// returned if noteworthy couldn't find anything.
-request_configuration()
-{
-    // try to find a notecard with our configuration.
-    pending_response_id = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([NOTEWORTHY_SIGNATURE, pending_response_id]);
-//call direct into noteworthy.
-noteworthy_handle_link_message(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND, parms_sent);
-        
-//    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-//         parms_sent);
-}
-
-// processes link messages received from the noteworthy library.
-handle_link_message(integer which, integer num, string msg, key id)
-{
-    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
-            || (msg != READ_NOTECARD_COMMAND) )
-        return;  // not for us.
-//log_it("handl: msg=" + msg + " id=" + id);
-    // process the result of reading the notecard.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string notecard_name = llList2String(parms, 0);
-//log_it("raw is " + llList2String(parms, 1));
-    integer response_for = llList2Integer(parms, 1);
-//log_it("resp cod=" + pending_response_id + " but this for=" + response_for);
-//if (response_for != pending_response_id) log_it("bad response code???");    
-    if (response_for != pending_response_id) return;  // oops, this isn't for us.
-    if (notecard_name == BAD_NOTECARD_INDICATOR) {
-        // we hated the notecards we found, or there were none.
-        log_it("We apologize; there seem to be no notecards with a first line of '"
-            + NOTEWORTHY_SIGNATURE
-            + "'.  We can't read any configuration until that situation improves.");
-    } else {
-//log_it("got to handle link");
-        // snag all but the first two elements for our config now.
-        global_config_list += llList2List(parms, 2, -1);
-        // make sure we shouldn't keep going.
-        if (notecard_name != NOTECARD_READ_CONTINUATION) {
-            // a valid notecard has been found.
-            global_config_index = 0;  // we are starting over in the config list.
-//            log_it("read notecard \"" + notecard_name + "\":");
-            // and process the file as a set of definitions.
-            process_ini_config();
-            // now that we have a new set of parameters, use them.
-            setup_seating_arrangements();
-        }
-    }
-}
-
-///////////////
-
-// consumes the notecard in a very application specific way to retrieve our configuration items.
-// the example script only looks for two variables: name and description.  if those are found in
-// the sample card, then they are proudly shown.
-parse_variable_definition(string to_parse)
-{
-    string content;  // filled after finding a variable name.
-    if ( (content = get_variable_value(to_parse, "avatar_rotation")) != "") {
-        AVATAR_ROTATION = (vector)content;
-//        log_it("** got avatar_rotation of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "avatar_position")) != "") {
-        AVATAR_POSITION = (vector)content;
-//        log_it("** got avatar_position of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "goto_which_floor")) != "") {
-        GOTO_WHICH_FLOOR = (integer)content;
-//        log_it("** got GOTO_WHICH_FLOOR of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "floor_size_in_meters")) != "") {
-        FLOOR_SIZE_IN_METERS = (float)content;
-//        log_it("** got FLOOR_SIZE_IN_METERS of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "base_floor_height")) != "") {
-        BASE_FLOOR_HEIGHT = (float)content;
-//        log_it("** got BASE_FLOOR_HEIGHT of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "unseat_afterwards")) != "") {
-        UNSEAT_AFTERWARDS = (integer)content;
-//        log_it("** got unseat_afterwards of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "pause_before_eviction")) != "") {
-        PAUSE_BEFORE_EVICTION = (float)content;
-//        log_it("** got pause_before_eviction of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "camera_eye_offset")) != "") {
-        CAMERA_EYE_OFFSET = (vector)content;
-//        log_it("** got camera_eye_offset of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "camera_target")) != "") {
-        CAMERA_TARGET = (vector)content;
-//        log_it("** got camera_target of '" + content + "'");
-//    } else {
-//        log_it("unknown variable seen: " + to_parse);
-    }
-}
-
-initialize()
-{
-    // reset our relevant variables.
-    global_config_list = [];
-    global_config_index = 0;
-
-    // announce that we're open for business.
-///    log_it("started, free mem=" + (string)llGetFreeMemory());
-
-    // request that the noteworthy library start looking for our notecard.
-    request_configuration();
-    
-    integer indy = 32;
-    while (indy >= 0) {
-        indy = find_in_inventory_partial("noteworthy", INVENTORY_SCRIPT);
-        if (indy >= 0) {
-            llRemoveInventory(llGetInventoryName(INVENTORY_SCRIPT, indy));
-        }
-    }
-    
-}
-
-//////////////
-// from hufflets...
-//
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// strips the spaces off of the beginning and end of a string.
-string strip_spaces(string to_strip)
-{
-    // clean out initial spaces.
-    while (llGetSubString(to_strip, 0, 0) == " ")
-        to_strip = llDeleteSubString(to_strip, 0, 0);
-    // clean out ending spaces.
-    while (llGetSubString(to_strip, -1, -1) == " ")
-        to_strip = llDeleteSubString(to_strip, -1, -1);
-    return to_strip;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-    return [ strip_spaces(x), strip_spaces(y) ];
-}
-
-// returns a non-empty string if "to_check" defines a value for "variable_name".
-// this must be in the form "X=Y", where X is the variable_name and Y is the value.
-string get_variable_value(string to_check, string variable_name)
-{
-    list x_y = separate_variable_definition(to_check);
-    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
-    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
-    return llList2String(x_y, 1);  // a match!
-}
-
-// examines all entries that we got from the notecard to see if any contain definitions.
-// this is basically an INI file reader, but it uses a list instead of a file.
-// ini files provide a format with multiple sections of config information, like so:
-//    [section_1]
-//    name1=value1
-//    name2=value2 ...etc...
-//    [section_2]
-//    name1=value1 ...etc...
-process_ini_config()
-{
-//    log_it("scanning notecard for variable definitions...");
-    integer indy;
-    integer count = llGetListLength(global_config_list);
-    string section_name;  // set later if we see one.
-
-    // iterate across the items in our configuration to look for ones that are not done yet.            
-    for (indy = global_config_index; indy < count; indy++) {
-        string line = llList2String(global_config_list, indy);
-        // search for a section beginning.
-        if (llGetSubString(line, 0, 0) == "[") {
-            // we found the start of a section name.  now read the contents.
-            indy++;  // skip section line.
-            section_name = llGetSubString(line, 1, -2);
-            log_it("reading section: " + section_name);
-        }
-        integer sec_indy;
-        for (sec_indy = indy; sec_indy < count; sec_indy++) {
-            // read the lines in the section.
-            line = llList2String(global_config_list, sec_indy);
-            if (llGetSubString(line, 0, 0) != "[") {
-                // try to interpret this line as a variable setting.  this is just
-                // one example of a way to handle the config file; one might instead
-                // want to do something below once a whole section is read.
-                parse_variable_definition(line);
-                indy = sec_indy;  // track that we've passed this line.
-            } else {
-                // we're at the beginning of a new section now, so start processing its
-                // configuration in the outer loop.
-                indy = sec_indy - 1;  // set indy to proper beginning of section.
-                global_config_index = indy;  // remember where we had read to.
-                sec_indy = count + 3;  // skip remainder of inner loop.
-            }
-        }
-    }
-
-    global_config_index = 0;  // reset outer position if want to re-read.
-}
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory_partial(string name_to_find, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 1.9.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-//
-// example usage of the auto-retirement script:
-//
-// default {
-//    state_entry() {
-//        auto_retire();  // make sure newest addition is only version of script.
-//    }
-// }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                if ((float)inv_version_string < (float)version_string) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
-        
-    string basename = to_chop_up;  // script name with no version attached.
-    
-    integer posn;
-    // minimum script name is 2 characters plus version.
-    for (posn = llStringLength(to_chop_up) - 1;
-        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
-        posn--) {
-        // find the space.  do nothing else.
-    }
-    if (posn < 2) return [];  // no space found.
-    string full_suffix = llGetSubString(to_chop_up, posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets
-//////////////
-
-//////////////
-// from noteworthy:
-
-// huffware script: noteworthy library, by fred huffhines.
-//
-// a handy approach to reading a notecard.  this version supports requiring
-// a 'signature' in the notecard's first line, so that multiple notecards can
-// exist in an object without being misinterpreted.  the script is accessed via
-// its link message API, so it can be used in an object without all this code
-// needing to be embedded in another script.  it also supports queuing up requests
-// to read notecards, so multiple scripts can use it to read their specific
-// notecards without any special handling (besides waiting a bit longer).
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants that can be adapted to your needs...
-
-integer DEBUGGING = FALSE;
-    // if this is true, then a lot of extra noise is generated when notecards are read.
-
-float TIME_OUT_ON_ONE_NOTECARD = 120.0;
-    // we allow one line of a notecard this long to be read before we decide it's hosed.
-    // some sims are very very slow, and a time-out of one minute has been found lacking;
-    // we saw at least one case where the first notecard line to be read took longer than
-    // 60 seconds.  that's why we keep cranking this time-out up...
-
-// constants that should not be changed...
-
-// outcomes from handling a line in a notecard.
-integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
-integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
-integer DONE_READING = -10;  // the notecard is finished being read.
-
-integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
-
-integer MAXIMUM_LINES_USED = 4;
-    // we will read this many lines at a time from the appropriate notecard.
-// global variables...
-
-string requested_signature = "";
-    // if this is non-empty, then it must be found in the first line of the script.
-
-integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
-
-string global_notecard_name;  // the name of the card we're reading now.
-key global_query_id = NULL_KEY;  // the identifier of our data query.
-integer current_response_code = 0;  // the code that our client uses for its reading.
-list global_query_contents;  // the lines we have read from the notecard.
-
-integer line_number = 0;  // which line are we at in notecard?
-
-integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
-
-integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
-
-list pending_signatures;  // signatures from queued requests for reading.
-list pending_response_codes;  // response codes for the queued requests.
-list pending_notecard_names;  // card names if it's a specific request.
-
-//////////////
-
-startup_initialize()
-{
-    llSetTimerEvent(0.0);
-    pending_signatures = [];
-    pending_response_codes = [];
-    pending_notecard_names = [];
-    current_response_code = 0;
-}
-
-reset_for_reading(string signature, integer response_code_in)
-{
-    requested_signature = signature;
-    current_response_code = response_code_in;
-    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
-    global_query_contents = [];
-    global_notecard_name = "";
-    line_number = 0;
-    found_signature_line = FALSE;
-    trying_notecard_at = -1;
-    global_query_id = NULL_KEY;
-}
-
-// use the existing global notecard setting to start reading.
-select_specific_notecard()
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    line_number = 0;  // reset line number again.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// picks the notecard at the "index" (from 0 to num_notecards - 1) and
-// starts reading it.
-select_notecard(integer index)
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
-    if (card_specified == "") return;   // not good.  bad index.
-    global_notecard_name = card_specified;
-    line_number = 0;  // reset line number again.
-    // we have a new file name, so load up the destinations, hopefully.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// increments our index in the count of notecards that the object has, and start
-// reading the next notecard (at the index).
-integer try_next_notecard()
-{
-    if (only_read_one_notecard) {
-        return FALSE;  // we were only going to try one.
-    }
-    // reset some values that might have applied before.
-    global_notecard_name = "";
-    // skip to the next card.
-    trying_notecard_at++;
-    // make sure we're not over the count of cards.
-    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
-        // this is a problem.  we didn't find anything suitable.
-        return FALSE;
-    }
-    // so, now we'll try the next notecard to look for our signature.
-    select_notecard(trying_notecard_at);
-    return TRUE;
-}
-
-// process a line of text that we received from the current notecard.
-integer handle_notecard_line(key query_id, string data)
-{
-    // if we're not at the end of the notecard we're reading...
-    if (data != EOF) {
-        // there's more to read in the notecard still.
-        if (data != "") {
-            // make sure we even have a signature to look for.
-            if (!found_signature_line && (requested_signature == "")) {
-                // no signature means that we always find it.
-                found_signature_line = TRUE;
-            }
-            // did we already get our signature?  if not, see if this is it.
-            if (!found_signature_line && (data != requested_signature) ) {
-                // this is a bad notecard.  skip it.
-                if (!try_next_notecard()) {
-                    // we have no more to work with.
-                    return BAD_NOTECARD;
-                }
-                return STILL_READING;  // we'll keep going.
-            } else if (!found_signature_line && (data == requested_signature) ) {
-                // this is a good signature line, so record that and then skip it.
-                found_signature_line = TRUE;
-            } else {
-                if (DEBUGGING
-                    && ( ( (requested_signature == "") && (line_number == 0) )
-                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
-                    log_it("started reading " + global_notecard_name + "...");
-                }
-                // don't record any lines that are comments.
-                if ( (llGetSubString(data, 0, 0) != "#")
-                    && (llGetSubString(data, 0, 0) != ";") ) {
-                    // add the non-blank line to our list.
-                    global_query_contents += data;
-                    // make sure we still have enough space to keep going.
-                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
-                        // ooh, make sure we pause before blowing our heap&stack.
-                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
-                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
-                    }
-                }
-            }
-        }
-        line_number++;  // increase the line count.
-        // reset the timer rather than timing out, if we actually got some data.
-        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
-        // request the next line from the notecard.
-        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
-        if (global_query_id == NULL_KEY) {
-//log_it("failed to restart notecard reading.");
-            return DONE_READING;
-//is that the best outcome?
-        }
-        return STILL_READING;
-    } else {
-        // that's the end of the notecard.  we need some minimal verification that it
-        // wasn't full of garbage.
-        if (!found_signature_line) {
-            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
-            if (!try_next_notecard()) {
-                return BAD_NOTECARD;  // we failed to find a good line?
-            } else {
-                // the next notecard's coming through now.
-                return STILL_READING;
-            }
-        } else {
-//            if (DEBUGGING) log_it("found signature.");
-            // saw the signature line, so this is a good one.
-            return DONE_READING;
-        }
-    }
-}
-
-// only sends reply; does not reset notecard process.
-send_reply(integer destination, list parms, string command,
-    integer include_query)
-{
-//log_it("froyo: curre code=" + current_response_code);
-//integer items = llGetListLength(parms);
-//if (include_query) items += llGetListLength(global_query_contents);
-//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
-
-   if (!include_query) {
-        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-    } else {
-        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command,
-            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
-    }
-    global_query_contents = [];
-//log_it("post-sending, mem=" + (string)llGetFreeMemory());
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply_and_reset(integer destination, list parms, string command,
-    integer include_query)
-{
-    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
-    send_reply(destination, parms, command, include_query);
-//log_it("about to reset response code");
-    current_response_code = 0;  // reset back to default so we can start another read.
-    global_query_id = NULL_KEY;  // reset so we accept no more data.
-}
-
-// if there are other pending notecard reads, this goes to the next one listed.
-dequeue_next_request()
-{
-    if (llGetListLength(pending_signatures)) {
-        // get the info from the next pending item.
-        string sig = llList2String(pending_signatures, 0);
-        integer response_code_temp = llList2Integer(pending_response_codes, 0);
-        string notecard = llList2String(pending_notecard_names, 0);
-        // whack the head of the queue since we grabbed the info.
-        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
-        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
-        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
-        if (llStringLength(notecard)) {
-            global_notecard_name = notecard;
-            select_specific_notecard();
-        } else {
-            reset_for_reading(sig, response_code_temp);
-        }
-    }
-}
-
-// deals with one data server answer from the notecard.
-process_notecard_line(key query_id, string data)
-{
-    // try to consume a line from the notecard.
-    integer outcome = handle_notecard_line(query_id, data);
-    if (outcome == DONE_READING) {
-        // that was a valid notecard and we read all of it.
-        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
-        // send back the results.
-        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
-            READ_NOTECARD_COMMAND, TRUE);
-    } else if (outcome == BAD_NOTECARD) {
-        // bail; this problem must be addressed by other means.
-        if (DEBUGGING) log_it("failed to find an appropriate notecard");
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    } else if (outcome == STILL_READING) {
-        // we have a good card and are still processing it.
-        return;
-    } else {
-        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
-        // again, bail out.  we have no idea what happened with this.
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    }
-    // if we have reached here, we should crank up the next queued notecard reading.
-    dequeue_next_request();
-}
-
-// processes requests from our users.
-noteworthy_handle_link_message(integer which, integer num, string msg, key id)
-{
-    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
-
-    if (msg == READ_NOTECARD_COMMAND) {
-        only_read_one_notecard = FALSE;  // general inquiry for any card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read notecard--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code_temp = llList2Integer(parms, 1);
-//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code_temp);
-            if (!try_next_notecard()) {
-                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
-                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code_temp ],
-                    READ_NOTECARD_COMMAND, FALSE);
-                return;
-            }
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code_temp;
-//holding:            pending_notecard_names += "";
-//holding:        }
-    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
-        only_read_one_notecard = TRUE;  // they want one particular card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read specific--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code_temp = llList2Integer(parms, 1);
-        string notecard_name = llList2String(parms, 2);
-//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code_temp);
-            global_notecard_name = notecard_name;  // set our global.
-            select_specific_notecard();
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code_temp;
-//holding:            pending_notecard_names += notecard_name;
-//holding:        }
-    }
-}
-
-    
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();  // make sure newest addition is only version of script.
-/////not needed now        llSleep(1.0);  // snooze just a bit to let noteworthy start up?
-        startup_initialize();
-        initialize();  // start asking about the notecards.
-        setup_seating_arrangements();  // use our current defaults for sitting posn.
-    }
-
-    on_rez(integer parm) { llResetScript(); }
-
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-//            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
-            llResetScript(); 
-        }
-        if (!(change & CHANGED_LINK)) return;  // don't care.
-        if (!UNSEAT_AFTERWARDS) return;  // nothing else below is needed.
-        if (llAvatarOnSitTarget() == NULL_KEY) return;  // no one there, so ditto.
-        // now give them a bit of time to rest before dumping them.
-        llSetTimerEvent(PAUSE_BEFORE_EVICTION);
-    }
-    
-    timer() {
-        if (current_response_code != 0) {
-            llSetTimerEvent(0.0);  // stop any timer now.
-            // let the caller know this has failed out.
-            if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
-            send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-                READ_NOTECARD_COMMAND, FALSE);
-            current_response_code = 0;  // we gave up on that one.
-            dequeue_next_request();  // get next reading started if we have anything to read.
-        } else {
-            // perform short range teleport, effectively...
-            llUnSit(llAvatarOnSitTarget());  // ha, got that guy back up.
-            llSetTimerEvent(0.0);  // reset timer.
-        }
-    }
-
-    // process the response from the noteworthy library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-
-    dataserver(key query_id, string data) {
-        // make sure this data is for us.
-        if (global_query_id != query_id) return;
-        // yep, seems to be.
-        process_notecard_line(query_id, data);
-    }            
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/die_on_demand_v0.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/die_on_demand_v0.3.lsl
new file mode 100755 (executable)
index 0000000..b0d5a44
--- /dev/null
@@ -0,0 +1,34 @@
+
+
+// huffware script: die on demand, by fred huffhines.
+//
+// a super simple script that merely makes an object subject to self-termination
+// if it is told a secret phrase.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+// API for the die on demand feature.  saying the message below on the channel
+// referenced will cause any listening object to zap itself out of the grid.
+string DIE_ON_DEMAND_MESSAGE = "die-on-demand";
+integer DIE_ON_DEMAND_CHANNEL = 4826;
+//////////////
+
+default
+{
+    state_entry()
+    {
+        llListen(DIE_ON_DEMAND_CHANNEL, "", NULL_KEY, "die-on-demand");
+    }
+    
+    listen(integer channel, string name, key id, string message) {
+        if ( (channel ==  DIE_ON_DEMAND_CHANNEL)
+            && (llGetOwnerKey(id) == llGetOwnerKey(llGetKey()))
+            && (message == DIE_ON_DEMAND_MESSAGE) ) {
+            llWhisper(0, "removing object.");
+            llDie();
+        }
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/die_on_demand_v0.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/die_on_demand_v0.3.txt
deleted file mode 100755 (executable)
index b0d5a44..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-// huffware script: die on demand, by fred huffhines.
-//
-// a super simple script that merely makes an object subject to self-termination
-// if it is told a secret phrase.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-// API for the die on demand feature.  saying the message below on the channel
-// referenced will cause any listening object to zap itself out of the grid.
-string DIE_ON_DEMAND_MESSAGE = "die-on-demand";
-integer DIE_ON_DEMAND_CHANNEL = 4826;
-//////////////
-
-default
-{
-    state_entry()
-    {
-        llListen(DIE_ON_DEMAND_CHANNEL, "", NULL_KEY, "die-on-demand");
-    }
-    
-    listen(integer channel, string name, key id, string message) {
-        if ( (channel ==  DIE_ON_DEMAND_CHANNEL)
-            && (llGetOwnerKey(id) == llGetOwnerKey(llGetKey()))
-            && (message == DIE_ON_DEMAND_MESSAGE) ) {
-            llWhisper(0, "removing object.");
-            llDie();
-        }
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/email_notecards_v6.0.lsl b/huffware/huffotronic_tools_n_testers_v6.1/email_notecards_v6.0.lsl
new file mode 100755 (executable)
index 0000000..16d198a
--- /dev/null
@@ -0,0 +1,381 @@
+
+// huffware script: email notecards, by fred huffhines.
+//
+// this script allows us to export notecards out of the grids.  it reads every notecard
+// that's dropped into the object, and then emails it to the specified recipient.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+
+
+//hmmm: need a command to clean up the inventory...
+//      among things that are not notecards, we need a way to clean up all inventory
+//      except the huffotronic updater and this script itself.
+
+
+// configure these for your own purposes:
+
+// the list of emails that should receive the notecard content.
+list EMAIL_LIST_FOR_NOTECARDS = [
+    "fred@spork.com"
+];
+
+// global constants...
+
+integer DEBUGGING = FALSE;  // if true, will make the run a lot noisier.
+
+float TIMER_PERIOD = 2.0;  // period for the timer to check on any pending notecards.
+
+// we'll keep our emails at or under this length.
+integer MAXIMUM_STRING_BUFFER = 3200;
+  // older versions of opensim have email limit of 1024 for sum of subject and body length.
+  // the documented behavior for lsl email is a max of 4096 for sum of subject and body length.
+
+vector TEXT_COLOR = <0.9, 0.7, 0.5>;  // the color the object's text will be painted with.
+
+// global variables....
+
+key current_query_id = NULL_KEY;  // the query ID for the current notecard.
+
+integer line_number;  // which line are we at in notecard?
+
+string current_notecard_name;  // we are reading a notecard named this, possibly.
+
+list pending_notecards;  // notecards that are going to be read eventually.
+
+integer processing_a_notecard = FALSE;  // are we currently reading and emailing a notecard?
+
+integer need_to_scan_notecards = FALSE;  // should the list of notecards be re-scanned?
+
+/////
+//hmmm: add to hufflets...
+
+// basic email sending, with some extra info passed along.
+send_email(string recipient, string subject, string content)
+{
+    if (DEBUGGING) log_it("before sending an email: " + subject);
+    llEmail(recipient, subject + " [via " + llKey2Name(llGetOwner()) + "]", content);
+    if (DEBUGGING) log_it("after sending an email: " + subject);
+}
+
+list __email_buffer;  // contents to send in email should pile up here.
+
+// sends out all the email that's pending in the __email_buffer variable.
+send_buffered_email(string subject)
+{
+    string temp_buffer;  // used to build up the email.
+    integer chunk_number = 1;  // tracks which part of the message this is.
+    integer i;
+    for (i = 0; i < llGetListLength(EMAIL_LIST_FOR_NOTECARDS); i++) {
+        string recip = llList2String(EMAIL_LIST_FOR_NOTECARDS, i);
+        temp_buffer = "";
+        integer j;
+        for (j = 0; j < llGetListLength(__email_buffer); j++) {
+            string line = llList2String(__email_buffer, j);        
+            if (llStringLength(temp_buffer) + llStringLength(line) >= MAXIMUM_STRING_BUFFER) {
+                // we're over our limit per email.  send out what we have and
+                // then freshen our buffer.
+                if (DEBUGGING)
+                    log_it("part " + chunk_number + " is " + llStringLength(temp_buffer) + " bytes.");
+                send_email(recip, subject + " (part " + chunk_number + ")", temp_buffer);
+                temp_buffer = "";
+                chunk_number++;
+            }
+            temp_buffer += llList2String(__email_buffer, j);
+        }
+        if (llStringLength(temp_buffer) > 0) {
+            // send the last piece of the email out.
+            if (DEBUGGING)
+                log_it("part " + chunk_number + " is " + llStringLength(temp_buffer) + " bytes.");
+            send_email(recip, subject + " (part " + chunk_number + ")", temp_buffer);
+        }
+    }
+    __email_buffer = [];  // clear the buffer now that the email is flying out.
+}
+////// add to hufflets end.
+////
+
+
+// reset any important variables and set up our assets and timers anat.
+initialize()
+{
+    current_query_id = NULL_KEY;
+    __email_buffer = [];
+    line_number = 0;
+        
+    llAllowInventoryDrop(TRUE);  // allow people to drop things into us.
+
+    // slap a title on the object.
+    string recip_list;
+    integer i;
+    for (i = 0; i < llGetListLength(EMAIL_LIST_FOR_NOTECARDS); i++) {
+        recip_list += "\n" + llList2String(EMAIL_LIST_FOR_NOTECARDS, i);
+    }
+    llSetText("Drop notecards into me\nto email them to:" + recip_list, TEXT_COLOR, 1.0);
+        
+    // set the timer to processing notecards that are pending.
+    reset_timer(TIMER_PERIOD);
+}
+
+//hmmm: add to hufflets?
+// safely reschedules the timer for a duration specified.
+// this gets around a gnarly SL bug where the timer stops working if not stopped first.
+reset_timer(float period)
+{
+    llSetTimerEvent(0.0);
+    llSetTimerEvent(period);
+}
+
+// starts reading the current notecard name, which should have been set elsewhere.
+consume_notecard()
+{
+    if (current_notecard_name == "") {
+        log_it("somehow we do not have a notecard to read in consume_notecard.");
+        return;
+    }
+    line_number = 0;
+    __email_buffer = [];
+    current_query_id = llGetNotecardLine(current_notecard_name, 0);    
+}
+
+// when the timer goes off, this checks our ongoing processes and kicks them
+// down the road a bit if they need it.
+handle_timer_pong()
+{
+    if (processing_a_notecard) return;  // already busy.
+    if (need_to_scan_notecards) {
+        queue_up_any_new_notecards();
+        need_to_scan_notecards = FALSE;
+    }
+
+    if (llGetListLength(pending_notecards) < 1) return;  // nothing to do.
+    processing_a_notecard = TRUE;
+    current_notecard_name = llList2String(pending_notecards, 0);
+    if (DEBUGGING) log_it("scheduling notecard: " + current_notecard_name);            
+    consume_notecard();
+}
+
+// processes the data chunks coming in from our notecard reading.
+handle_data_arriving(key query_id, string data)
+{
+    if (query_id != current_query_id) {
+        if (DEBUGGING) log_it("not our query id somehow?");
+        return;
+    }
+    // if we're not at the end of the notecard we're reading...
+    if (data != EOF) {
+        if (!line_number) {
+            if (DEBUGGING) log_it("starting to read notecard " + current_notecard_name + "...");    
+        }
+        // add the line to our destination list.
+        if (is_prefix(data, "From")) data = "#" + data;  // voodoo.
+        __email_buffer += [ data + "\n" ];
+        if (DEBUGGING) log_it("line " + (string)line_number + ": data=" + data);
+        line_number++;  // increase the line count.
+        // request the next line from the notecard.
+        current_query_id = llGetNotecardLine(current_notecard_name, line_number);
+    } else {
+        // no more data, so we're done with this card.
+        current_query_id = NULL_KEY;
+        // blast out the notecard's content in an email.
+        llSay(0, "Sending \"" + current_notecard_name + "\" with " + line_number + " lines.\n");
+        send_buffered_email(current_notecard_name);
+        // chop that name out of our current pending cards too.
+        integer where = llListFindList(pending_notecards, [current_notecard_name]);
+//log_it("found the notecard to remove at index " + where);        
+        if (where >= 0) {
+            pending_notecards = llDeleteSubList(pending_notecards, where, where);
+        }
+        // done with it, so eat the current note card.
+        llRemoveInventory(current_notecard_name);
+        llSay(0, "Done with notecard \"" + current_notecard_name + "\"; now removing it.");
+        // reset our flag to signal that we're ready to eat another notecard.
+        processing_a_notecard = FALSE;        
+        current_notecard_name = "";
+        // make sure we have all current notecards queued.
+        need_to_scan_notecards = TRUE;
+        // push timer out.
+        reset_timer(TIMER_PERIOD);
+    }
+}
+
+// look through our inventory and if there are any notecards we don't know about,
+// add them to the list for processing.
+queue_up_any_new_notecards()
+{
+    integer i;
+    for (i = 0; i < llGetInventoryNumber(INVENTORY_NOTECARD); i++) {
+        string note_name = llGetInventoryName(INVENTORY_NOTECARD, i);
+        // don't add the notecard if the name is already listed.
+        integer where = llListFindList(pending_notecards, [ note_name ]);
+        if (where >= 0) {
+//            if (DEBUGGING) log_it("notecard already present; skipping: " + note_name);
+        } else {
+            // schedule notecard reading by adding to queue.
+            pending_notecards += [ note_name ];
+//            if (DEBUGGING) log_it("notecard added to pending: " + note_name);
+        }
+    }
+}
+
+//////////////
+
+// borrowed from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+//////////////
+
+// the string processing methods are not case sensitive.
+  
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end from hufflets.
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        initialize();
+    }
+    
+    changed(integer mask) {
+        if (mask & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY)) {
+            need_to_scan_notecards = TRUE;
+            pending_notecards = [];  // reset the list so we re-add all and drop any dead ones.
+            reset_timer(TIMER_PERIOD);
+        }
+    }
+    
+    timer() { handle_timer_pong(); }
+    
+    dataserver(key query_id, string data) { handle_data_arriving(query_id, data); }        
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/email_notecards_v6.0.txt b/huffware/huffotronic_tools_n_testers_v6.1/email_notecards_v6.0.txt
deleted file mode 100755 (executable)
index 16d198a..0000000
+++ /dev/null
@@ -1,381 +0,0 @@
-
-// huffware script: email notecards, by fred huffhines.
-//
-// this script allows us to export notecards out of the grids.  it reads every notecard
-// that's dropped into the object, and then emails it to the specified recipient.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-
-
-//hmmm: need a command to clean up the inventory...
-//      among things that are not notecards, we need a way to clean up all inventory
-//      except the huffotronic updater and this script itself.
-
-
-// configure these for your own purposes:
-
-// the list of emails that should receive the notecard content.
-list EMAIL_LIST_FOR_NOTECARDS = [
-    "fred@spork.com"
-];
-
-// global constants...
-
-integer DEBUGGING = FALSE;  // if true, will make the run a lot noisier.
-
-float TIMER_PERIOD = 2.0;  // period for the timer to check on any pending notecards.
-
-// we'll keep our emails at or under this length.
-integer MAXIMUM_STRING_BUFFER = 3200;
-  // older versions of opensim have email limit of 1024 for sum of subject and body length.
-  // the documented behavior for lsl email is a max of 4096 for sum of subject and body length.
-
-vector TEXT_COLOR = <0.9, 0.7, 0.5>;  // the color the object's text will be painted with.
-
-// global variables....
-
-key current_query_id = NULL_KEY;  // the query ID for the current notecard.
-
-integer line_number;  // which line are we at in notecard?
-
-string current_notecard_name;  // we are reading a notecard named this, possibly.
-
-list pending_notecards;  // notecards that are going to be read eventually.
-
-integer processing_a_notecard = FALSE;  // are we currently reading and emailing a notecard?
-
-integer need_to_scan_notecards = FALSE;  // should the list of notecards be re-scanned?
-
-/////
-//hmmm: add to hufflets...
-
-// basic email sending, with some extra info passed along.
-send_email(string recipient, string subject, string content)
-{
-    if (DEBUGGING) log_it("before sending an email: " + subject);
-    llEmail(recipient, subject + " [via " + llKey2Name(llGetOwner()) + "]", content);
-    if (DEBUGGING) log_it("after sending an email: " + subject);
-}
-
-list __email_buffer;  // contents to send in email should pile up here.
-
-// sends out all the email that's pending in the __email_buffer variable.
-send_buffered_email(string subject)
-{
-    string temp_buffer;  // used to build up the email.
-    integer chunk_number = 1;  // tracks which part of the message this is.
-    integer i;
-    for (i = 0; i < llGetListLength(EMAIL_LIST_FOR_NOTECARDS); i++) {
-        string recip = llList2String(EMAIL_LIST_FOR_NOTECARDS, i);
-        temp_buffer = "";
-        integer j;
-        for (j = 0; j < llGetListLength(__email_buffer); j++) {
-            string line = llList2String(__email_buffer, j);        
-            if (llStringLength(temp_buffer) + llStringLength(line) >= MAXIMUM_STRING_BUFFER) {
-                // we're over our limit per email.  send out what we have and
-                // then freshen our buffer.
-                if (DEBUGGING)
-                    log_it("part " + chunk_number + " is " + llStringLength(temp_buffer) + " bytes.");
-                send_email(recip, subject + " (part " + chunk_number + ")", temp_buffer);
-                temp_buffer = "";
-                chunk_number++;
-            }
-            temp_buffer += llList2String(__email_buffer, j);
-        }
-        if (llStringLength(temp_buffer) > 0) {
-            // send the last piece of the email out.
-            if (DEBUGGING)
-                log_it("part " + chunk_number + " is " + llStringLength(temp_buffer) + " bytes.");
-            send_email(recip, subject + " (part " + chunk_number + ")", temp_buffer);
-        }
-    }
-    __email_buffer = [];  // clear the buffer now that the email is flying out.
-}
-////// add to hufflets end.
-////
-
-
-// reset any important variables and set up our assets and timers anat.
-initialize()
-{
-    current_query_id = NULL_KEY;
-    __email_buffer = [];
-    line_number = 0;
-        
-    llAllowInventoryDrop(TRUE);  // allow people to drop things into us.
-
-    // slap a title on the object.
-    string recip_list;
-    integer i;
-    for (i = 0; i < llGetListLength(EMAIL_LIST_FOR_NOTECARDS); i++) {
-        recip_list += "\n" + llList2String(EMAIL_LIST_FOR_NOTECARDS, i);
-    }
-    llSetText("Drop notecards into me\nto email them to:" + recip_list, TEXT_COLOR, 1.0);
-        
-    // set the timer to processing notecards that are pending.
-    reset_timer(TIMER_PERIOD);
-}
-
-//hmmm: add to hufflets?
-// safely reschedules the timer for a duration specified.
-// this gets around a gnarly SL bug where the timer stops working if not stopped first.
-reset_timer(float period)
-{
-    llSetTimerEvent(0.0);
-    llSetTimerEvent(period);
-}
-
-// starts reading the current notecard name, which should have been set elsewhere.
-consume_notecard()
-{
-    if (current_notecard_name == "") {
-        log_it("somehow we do not have a notecard to read in consume_notecard.");
-        return;
-    }
-    line_number = 0;
-    __email_buffer = [];
-    current_query_id = llGetNotecardLine(current_notecard_name, 0);    
-}
-
-// when the timer goes off, this checks our ongoing processes and kicks them
-// down the road a bit if they need it.
-handle_timer_pong()
-{
-    if (processing_a_notecard) return;  // already busy.
-    if (need_to_scan_notecards) {
-        queue_up_any_new_notecards();
-        need_to_scan_notecards = FALSE;
-    }
-
-    if (llGetListLength(pending_notecards) < 1) return;  // nothing to do.
-    processing_a_notecard = TRUE;
-    current_notecard_name = llList2String(pending_notecards, 0);
-    if (DEBUGGING) log_it("scheduling notecard: " + current_notecard_name);            
-    consume_notecard();
-}
-
-// processes the data chunks coming in from our notecard reading.
-handle_data_arriving(key query_id, string data)
-{
-    if (query_id != current_query_id) {
-        if (DEBUGGING) log_it("not our query id somehow?");
-        return;
-    }
-    // if we're not at the end of the notecard we're reading...
-    if (data != EOF) {
-        if (!line_number) {
-            if (DEBUGGING) log_it("starting to read notecard " + current_notecard_name + "...");    
-        }
-        // add the line to our destination list.
-        if (is_prefix(data, "From")) data = "#" + data;  // voodoo.
-        __email_buffer += [ data + "\n" ];
-        if (DEBUGGING) log_it("line " + (string)line_number + ": data=" + data);
-        line_number++;  // increase the line count.
-        // request the next line from the notecard.
-        current_query_id = llGetNotecardLine(current_notecard_name, line_number);
-    } else {
-        // no more data, so we're done with this card.
-        current_query_id = NULL_KEY;
-        // blast out the notecard's content in an email.
-        llSay(0, "Sending \"" + current_notecard_name + "\" with " + line_number + " lines.\n");
-        send_buffered_email(current_notecard_name);
-        // chop that name out of our current pending cards too.
-        integer where = llListFindList(pending_notecards, [current_notecard_name]);
-//log_it("found the notecard to remove at index " + where);        
-        if (where >= 0) {
-            pending_notecards = llDeleteSubList(pending_notecards, where, where);
-        }
-        // done with it, so eat the current note card.
-        llRemoveInventory(current_notecard_name);
-        llSay(0, "Done with notecard \"" + current_notecard_name + "\"; now removing it.");
-        // reset our flag to signal that we're ready to eat another notecard.
-        processing_a_notecard = FALSE;        
-        current_notecard_name = "";
-        // make sure we have all current notecards queued.
-        need_to_scan_notecards = TRUE;
-        // push timer out.
-        reset_timer(TIMER_PERIOD);
-    }
-}
-
-// look through our inventory and if there are any notecards we don't know about,
-// add them to the list for processing.
-queue_up_any_new_notecards()
-{
-    integer i;
-    for (i = 0; i < llGetInventoryNumber(INVENTORY_NOTECARD); i++) {
-        string note_name = llGetInventoryName(INVENTORY_NOTECARD, i);
-        // don't add the notecard if the name is already listed.
-        integer where = llListFindList(pending_notecards, [ note_name ]);
-        if (where >= 0) {
-//            if (DEBUGGING) log_it("notecard already present; skipping: " + note_name);
-        } else {
-            // schedule notecard reading by adding to queue.
-            pending_notecards += [ note_name ];
-//            if (DEBUGGING) log_it("notecard added to pending: " + note_name);
-        }
-    }
-}
-
-//////////////
-
-// borrowed from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-//////////////
-
-// the string processing methods are not case sensitive.
-  
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end from hufflets.
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        initialize();
-    }
-    
-    changed(integer mask) {
-        if (mask & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY)) {
-            need_to_scan_notecards = TRUE;
-            pending_notecards = [];  // reset the list so we re-add all and drop any dead ones.
-            reset_timer(TIMER_PERIOD);
-        }
-    }
-    
-    timer() { handle_timer_pong(); }
-    
-    dataserver(key query_id, string data) { handle_data_arriving(query_id, data); }        
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/hamster_sound_effects_v0.8.lsl b/huffware/huffotronic_tools_n_testers_v6.1/hamster_sound_effects_v0.8.lsl
new file mode 100755 (executable)
index 0000000..163bc38
--- /dev/null
@@ -0,0 +1,38 @@
+
+// huffware script: hamster sound effects, by fred huffhines
+//
+// a randomizing sound player, originally used to replace a sound
+// playing script with bad perms in a freebie hamster.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+list all_sounds;
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry() {
+        llStopSound();
+        integer indy;
+        for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SOUND); indy++) {
+            all_sounds += [ llGetInventoryName(INVENTORY_SOUND, indy) ];
+        }
+    }
+
+    touch_start(integer cnt) {
+        all_sounds = llListRandomize(all_sounds, 1);
+        llTriggerSound(llList2String(all_sounds, 0), 1.0);
+    }
+    
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) llResetScript();  // reset when sounds might have changed.
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/hamster_sound_effects_v0.8.txt b/huffware/huffotronic_tools_n_testers_v6.1/hamster_sound_effects_v0.8.txt
deleted file mode 100755 (executable)
index 163bc38..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-
-// huffware script: hamster sound effects, by fred huffhines
-//
-// a randomizing sound player, originally used to replace a sound
-// playing script with bad perms in a freebie hamster.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-list all_sounds;
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry() {
-        llStopSound();
-        integer indy;
-        for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SOUND); indy++) {
-            all_sounds += [ llGetInventoryName(INVENTORY_SOUND, indy) ];
-        }
-    }
-
-    touch_start(integer cnt) {
-        all_sounds = llListRandomize(all_sounds, 1);
-        llTriggerSound(llList2String(all_sounds, 0), 1.0);
-    }
-    
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) llResetScript();  // reset when sounds might have changed.
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/html_onna_prim_v1.6.lsl b/huffware/huffotronic_tools_n_testers_v6.1/html_onna_prim_v1.6.lsl
new file mode 100755 (executable)
index 0000000..1edb2fd
--- /dev/null
@@ -0,0 +1,131 @@
+
+// huffware script: html onna prim, by fred huffhines.
+//
+// sets the land's media to a web site.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer initted = FALSE;
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 1.9.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+//
+// example usage of the auto-retirement script:
+//
+// default {
+//    state_entry() {
+//        auto_retire();  // make sure newest addition is only version of script.
+//    }
+// }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                if ((float)inv_version_string < (float)version_string) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
+        
+    string basename = to_chop_up;  // script name with no version attached.
+    
+    integer posn;
+    // minimum script name is 2 characters plus version.
+    for (posn = llStringLength(to_chop_up) - 1;
+        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
+        posn--) {
+        // find the space.  do nothing else.
+    }
+    if (posn < 2) return [];  // no space found.
+    string full_suffix = llGetSubString(to_chop_up, posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+
+    }
+    
+    on_rez(integer parm) {
+        llResetScript();
+    }
+    
+    touch_start(integer count) {
+        if ( llParcelMediaQuery([PARCEL_MEDIA_COMMAND_TEXTURE]) == [] ) {
+            llSay(0, "Lacking permission to set/query parcel media. This object has to be owned by/deeded to the land owner.");
+            return;
+        }
+        if (!initted) {
+            string texture_name = llGetInventoryName(INVENTORY_TEXTURE, 0);
+            // sets the media texture to the first texture found in our inventory.
+            llParcelMediaCommandList( [
+                PARCEL_MEDIA_COMMAND_URL, "http://gruntose.com",
+                PARCEL_MEDIA_COMMAND_TYPE, "text/html",
+                PARCEL_MEDIA_COMMAND_TEXTURE, llGetInventoryKey(texture_name),
+                PARCEL_MEDIA_COMMAND_PLAY ] );
+            llSetTexture(texture_name, ALL_SIDES);
+            initted = TRUE;
+        }
+        
+        // zap it again.
+        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
+        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/html_onna_prim_v1.6.txt b/huffware/huffotronic_tools_n_testers_v6.1/html_onna_prim_v1.6.txt
deleted file mode 100755 (executable)
index 1edb2fd..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-
-// huffware script: html onna prim, by fred huffhines.
-//
-// sets the land's media to a web site.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer initted = FALSE;
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 1.9.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-//
-// example usage of the auto-retirement script:
-//
-// default {
-//    state_entry() {
-//        auto_retire();  // make sure newest addition is only version of script.
-//    }
-// }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                if ((float)inv_version_string < (float)version_string) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
-        
-    string basename = to_chop_up;  // script name with no version attached.
-    
-    integer posn;
-    // minimum script name is 2 characters plus version.
-    for (posn = llStringLength(to_chop_up) - 1;
-        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
-        posn--) {
-        // find the space.  do nothing else.
-    }
-    if (posn < 2) return [];  // no space found.
-    string full_suffix = llGetSubString(to_chop_up, posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-
-    }
-    
-    on_rez(integer parm) {
-        llResetScript();
-    }
-    
-    touch_start(integer count) {
-        if ( llParcelMediaQuery([PARCEL_MEDIA_COMMAND_TEXTURE]) == [] ) {
-            llSay(0, "Lacking permission to set/query parcel media. This object has to be owned by/deeded to the land owner.");
-            return;
-        }
-        if (!initted) {
-            string texture_name = llGetInventoryName(INVENTORY_TEXTURE, 0);
-            // sets the media texture to the first texture found in our inventory.
-            llParcelMediaCommandList( [
-                PARCEL_MEDIA_COMMAND_URL, "http://gruntose.com",
-                PARCEL_MEDIA_COMMAND_TYPE, "text/html",
-                PARCEL_MEDIA_COMMAND_TEXTURE, llGetInventoryKey(texture_name),
-                PARCEL_MEDIA_COMMAND_PLAY ] );
-            llSetTexture(texture_name, ALL_SIDES);
-            initted = TRUE;
-        }
-        
-        // zap it again.
-        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
-        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/huff-update_client_v20.1.lsl b/huffware/huffotronic_tools_n_testers_v6.1/huff-update_client_v20.1.lsl
new file mode 100755 (executable)
index 0000000..4a458bb
--- /dev/null
@@ -0,0 +1,826 @@
+
+// huffware script: huff-update client, by fred huffhines.
+//
+// this script is the client side of the update process.  it should reside in an object that
+// has scripts which should be automatically updated.  it will listen for announcements by
+// an update server and communicate with the server to ensure that all of its scripts are
+// the most up to date available with the server.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+integer DEBUGGING = FALSE;  // if TRUE, the script will output status information.
+
+integer SERVER_IGNORE_TIME = 1200;  // number of seconds between performing an upgrade with the same server.
+
+integer MAXIMUM_UPDATE_TIME_ALLOWED = 140;  // we allow one upgrade process to take this long overall.
+
+integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
+integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
+
+string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
+string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
+string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
+string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
+string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
+string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
+string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
+string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
+string DONE_UPDATING                = "#finito#";  // the client is done updating.
+string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
+
+float UPDATE_TIMER_INTERVAL = 2.0;  // interval between checks on our update status.
+
+integer UPDATER_SCRIPT_PIN = -1231008;  // the hook for our scripts to be modified.
+
+///float BUSY_SERVER_PAUSE_TIME = 38.0;  // num seconds to delay when server says it's too busy.
+
+string UPDATER_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+
+string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
+string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
+
+integer MAXIMUM_SERVERS_TRACKED = 32;
+    // we will listen to this many servers before we decide to remove one.
+
+string CONTINUANCE_MARKER = "...";
+    // a string sent when the update list is too long and needs to be continued in another chat.
+
+string SERVER_SCRIPT = "a huffotronic update server";
+    // the prefix of our server script that hands out updates.
+
+// global variables...
+
+integer inventory_request_channel;  // used for newer version servers to cut down cross chatter.
+list updaters_heard;  // the update servers we've heard from recently.
+list last_interactions;  // times of the last update process engaged with the updater.
+integer update_channel;  // current channel for interaction with specific server.
+key current_server;  // the updater that is active right now, if any.
+integer update_start_time;  // when the last update process began.
+list updates_needed;  // stores the set of scripts that are in need of an update.
+list known_script_dependencies;  // stores the list of dependency info.
+
+careful_crankup()
+{
+    knock_around_other_scripts(TRUE);
+    // clean out the older items and scripts.  we do this after getting everyone running
+    // since we might be whacking ourselves.
+    destroy_older_versions();
+}
+
+// reset our variables.
+initialize()
+{
+    updaters_heard = [];
+    last_interactions = [];
+    inventory_request_channel = 0;
+    update_channel = 0;
+    current_server = NULL_KEY;
+    llSetTimerEvent(0.0);
+    llSetRemoteScriptAccessPin(UPDATER_SCRIPT_PIN);
+    // a new enhancements; tells the server that this guy has finished an update cycle.  this
+    // only comes into play when the updater script itself has just been updated, but it's
+    // nice for the server to avoid claiming erroneous timeouts occurred.
+    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
+    llSleep(0.4);  // snooze and repeat to overcome occasionally lossy chats.
+    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
+}
+
+whack_updater_record(key id)
+{
+    integer prev_indy = find_in_list(updaters_heard, id);
+    if (prev_indy < 0) return;  // not there.
+    updaters_heard = chop_list(updaters_heard, 0, prev_indy - 1)
+            + chop_list(updaters_heard, prev_indy + 1, llGetListLength(updaters_heard) - 1);
+    last_interactions = chop_list(last_interactions, 0, prev_indy - 1)
+            + chop_list(last_interactions, prev_indy + 1, llGetListLength(last_interactions) - 1);
+}
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        if (DEBUGGING)
+            log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+    // thirdly, try to clean out the notecards.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
+}
+
+// sets the object to be listening for update info.
+// if "just_owner" is true, then we will not listen on the general announcement channel.
+listen_for_orders(integer just_owner)
+{
+    if (!just_owner) {
+        // try to hear an update being announced.
+        llListen(UPDATE_ANNOUNCEMENT_CHANNEL, "", NULL_KEY, "");
+    }
+
+    // super secret owner controls.
+    llListen(0, "", llGetOwner(), "");
+}
+
+// returns true if this object is a huffotronic updater of some sort.
+integer inside_of_updater()
+{
+    return find_substring(llGetObjectName(), "huffotronic") >= 0;
+}
+
+// returns true if a script is a version of our update server.
+integer matches_server_script(string to_check)
+{
+    return is_prefix(to_check, SERVER_SCRIPT);
+}
+
+// stops all the scripts besides this one.
+knock_around_other_scripts(integer running_state)
+{
+    integer insider = inside_of_updater();
+    if (running_state == TRUE) {
+        // make sure we crank up the scripts that are new first.  we want to reset them
+        // as well, which we don't want to do for any existing scripts.
+        integer crank_indy;
+        for (crank_indy = 0; crank_indy < llGetListLength(updates_needed); crank_indy++) {
+            string crankee = llList2String(updates_needed, crank_indy);
+            if (find_in_inventory(crankee, INVENTORY_SCRIPT, TRUE) >= 0) {
+                if (!insider || matches_server_script(crankee)) {
+                    // allow it to run again.
+                    llSetScriptState(crankee, TRUE);
+                    // reset it, to make sure it starts at the top.
+                    llResetOtherScript(crankee);
+                }
+            }
+        }
+    }
+
+    integer indy;
+    string self_script = llGetScriptName();
+    // we set all other scripts to the running state requested.
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if ( (curr_script != self_script)
+            && (!insider || matches_server_script(curr_script)) ) {
+            // this one seems ripe for being set to the state requested.
+            llSetScriptState(curr_script, running_state);
+        }
+    }
+}
+
+// a random channel for the interaction with the server.
+integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
+
+// make sure that any dependencies for the script with "basename" are added to the list
+// of requests we make during an update.
+list add_dependencies(string basename)
+{
+    list to_return;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(known_script_dependencies); indy++) {
+        list deps = llParseString2List(llList2String(known_script_dependencies, indy),
+            [ITEM_LIST_SEPARATOR], []);
+//log_it("base=" + llList2String(dep, 0) + " lastver=" + llList2String(dep, 1) + " newdep=" + llList2String(dep, 2));
+        if (basename == llList2String(deps, 0)) {
+            // first off, is this item with new dependencies actually present?
+            integer where = find_in_inventory(basename, INVENTORY_SCRIPT, FALSE);
+            if (where >= 0) {
+                // we do use the script with deps, but is the dependent item really missing?
+                where = find_in_inventory(llList2String(deps, 1), INVENTORY_SCRIPT, FALSE);
+                if (where < 0) {
+                    // we found a dependency match for this script, so we'll ask for the missing item.
+                    if (DEBUGGING)
+                        log_it("missing dep: " + llList2String(deps, 1));
+                    to_return += [ llList2String(deps, 1) ];
+                }
+            }
+        }
+    }
+    return to_return;
+}
+
+// complains if memory seems to be getting tight.
+test_memory()
+{
+    if (llGetFreeMemory() < 4096)
+        log_it("mem_free = " + (string)llGetFreeMemory());
+}
+
+// starts an update given a list of scripts that the server has available, encoded as
+// a string in the "encoded_list".
+integer initiate_update(string encoded_list)
+{
+    list scripts_avail = llParseString2List(encoded_list, [UPDATER_PARM_SEPARATOR], []);
+    integer continue_listening_for_scripts = FALSE;
+      // if true, we aren't done hearing about available scripts yet.
+    encoded_list = "";
+    // figure out which scripts we need by comparing the list available from the server
+    // against our current inventory.  we only want scripts with newer version numbers.
+    integer sindy;
+    for (sindy = 0; sindy < llGetListLength(scripts_avail); sindy++) {
+        string curr = llList2String(scripts_avail, sindy);
+        if (curr == CONTINUANCE_MARKER) {
+            // this is a special continuation signal.  we need to hear the rest of the list.
+            continue_listening_for_scripts = TRUE;
+        } else if (is_prefix(curr, SCRIPT_DEPENDENCY_MARK)) {
+            // we've found a dependency item.
+            known_script_dependencies += [ llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1) ];
+//log_it("script dep: " + llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1));
+        } else {
+            list split = compute_basename_and_version(curr);
+            if (llGetListLength(split) == 2) {
+                string basename = llList2String(split, 0);
+                string version = llList2String(split, 1);
+                split = [];
+                integer oy_indy;
+//replace common code with func.
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_OBJECT); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_OBJECT, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+//                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+//                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_NOTECARD); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_NOTECARD, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_SCRIPT); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_SCRIPT, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                updates_needed += add_dependencies(basename);
+            }
+        }
+    }
+    // we skip the next step if we're still waiting to hear about more.
+    if (continue_listening_for_scripts) {
+//log_it("still listening for more updates...");
+        return FALSE;
+    }
+    if (llGetListLength(updates_needed)) {
+//log_it("update chan=" + (string)update_channel);
+        llSay(update_channel, REQUEST_SCRIPT_UPDATE);
+        if (DEBUGGING) {
+            log_it("told server " + (string)inventory_request_channel + " that i need updating.");
+        }
+    } else {
+        if (DEBUGGING) {
+            log_it("told server " + (string)inventory_request_channel + " that i am done updating.");
+        }
+        llSay(update_channel, DONE_UPDATING);
+    }
+    return TRUE;
+}    
+
+// this alerts the server to our most desired scripts.
+tell_server_our_wish_list()
+{
+    llSay(update_channel, READY_TO_UPDATE + wrap_parameters(updates_needed));
+}
+
+// checks whether all of the updates needed are present yet.
+integer check_on_update_presence()
+{
+    integer indy;
+    for (indy = 0; indy < llGetListLength(updates_needed); indy++) {
+        integer found = find_in_inventory(llList2String(updates_needed, indy), INVENTORY_ALL, TRUE);
+        // any single missing guy means they aren't up to date yet.
+        if (found < 0) {
+            if (DEBUGGING) log_it(llList2String(updates_needed, indy) + " not seen as updated yet.");
+            return FALSE;
+        }
+    }
+    // nothing was detected as missing anymore.
+    return TRUE;
+}
+
+// respond to spoken commands from the server.
+integer process_update_news(integer channel, string name, key id, string message)
+{
+    if (!channel) {
+        // this is a command.
+        if (message == "ureset") {
+            llResetScript();  // start over.
+        }
+        if (message == "ushow") {
+            integer sindy;
+            integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
+            list script_list = [ "scripts--" ];  // first item is just a header.
+            for (sindy = 0; sindy < script_count; sindy++) {
+                script_list += [ llGetInventoryName(INVENTORY_SCRIPT, sindy) ];
+            }
+            dump_list_to_log(script_list);
+        }
+        return FALSE;  // nothing to do here.
+    }
+    if (!update_channel && (channel == UPDATE_ANNOUNCEMENT_CHANNEL)) {
+/* never seen.        if (id == llGetKey()) {
+if (DEBUGGING) log_it("ignoring update from self.");            
+            return FALSE;  // ack, that's our very object.
+        }
+*/
+        if (llStringLength(message) > llStringLength(UPDATE_ANNOUNCEMENT_PREFIX)) {
+            // this is a new style update message.  we can set a different request channel.
+            string just_chan = llDeleteSubString(message, 0, llStringLength(UPDATE_ANNOUNCEMENT_PREFIX) - 1);
+            inventory_request_channel = (integer)just_chan;
+        }
+        integer prev_indy = find_in_list(updaters_heard, id);
+        // find the talker in our list.
+        if (prev_indy >= 0) {
+            // that guy was already heard from.  check when last interacted.
+            integer last_heard = llList2Integer(last_interactions, prev_indy);
+            if (llAbs(llGetUnixTime() - last_heard) < SERVER_IGNORE_TIME) {
+                return FALSE;  // not time to update with this guy again yet.
+            }
+//            if (DEBUGGING) { log_it("started listening again to server " + (string)id); }
+            // make sure we think of this as a new updater now.
+            whack_updater_record(id);
+        }
+
+        if (DEBUGGING) { log_it("heard server " + (string)inventory_request_channel + "'s announcement."); }
+        // record our new server.
+        current_server = id;
+        // make a random pause so not all updaters try to crank up at same time.
+        llSleep(randomize_within_range(2.8, 18.2, FALSE));
+
+        if (llGetListLength(updaters_heard) > MAXIMUM_SERVERS_TRACKED) {
+            // oops, this is not good.  we have too many servers now.
+//hmmm: room for improvement here by tossing out the server that is oldest.
+            updaters_heard = llDeleteSubList(updaters_heard, 0, 0);
+            last_interactions = llDeleteSubList(last_interactions, 0, 0);
+        }
+        
+        // add the talker to our list.
+        updaters_heard += id;
+        last_interactions += llGetUnixTime();
+    
+        // begin the update interaction with this guy.
+        update_channel = random_channel();
+        return TRUE;
+    }
+    if (update_channel && (channel == update_channel) ) {
+        if (is_prefix(message, REPORT_AVAILABLE_SCRIPTS)) {
+            // tasty, this is a list of scripts that can be had.
+            message = llDeleteSubString(message, 0, llStringLength(REPORT_AVAILABLE_SCRIPTS) - 1);
+            if (message == BUSY_BUSY) {
+                // server has signified that it's too busy (or its owner is a moron) because it is
+                // claiming it has no scripts at all.
+                if (DEBUGGING) {
+                    log_it("server " + (string)inventory_request_channel + " is too busy to update us now.");
+                }
+                // make it seem like we need to do this one again sooner than normal.
+                whack_updater_record(id);
+                // busy server means move no further forward.
+                return FALSE;
+            }
+            return initiate_update(message);
+        } else if (is_prefix(message, SHUT_THEM_DOWN)) {
+            if (DEBUGGING) { log_it("stopping other scripts."); }
+            knock_around_other_scripts(FALSE);
+            // now that we know for sure the server's ready to update us,
+            // we tell it what we need.
+            tell_server_our_wish_list();
+            return FALSE;
+        } else if (is_prefix(message, START_THEM_UP)) {
+            // let the server know that we've finished, for all intents and purposes.
+            llSay(update_channel, DONE_UPDATING);
+            // we pause a random bit first; we want to ensure we aren't swamping
+            // SL with our inventory loading.
+            llSleep(randomize_within_range(2.5, 8.2, FALSE));
+            if (DEBUGGING) { log_it("starting other scripts."); }
+            careful_crankup();
+            return TRUE;  // change state now.
+//        } else {
+//log_it("unknown command on update channel: " + message);
+        }
+    }
+    return FALSE;
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    llWhisper(0, llGetScriptName() + " [" + (string)debug_num + "] (" + (string)llGetFreeMemory() + ") " + to_say);
+}
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type, integer exact_match)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (exact_match && (llGetInventoryName(inv_type, inv) == name_to_find) )
+            return inv;
+        else if (!exact_match && is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+//////////////
+
+integer MAX_CHAT_LINE = 900;
+    // the most characters we'll try to say in one chat.
+
+dump_list_to_log(list to_show)
+{
+    string text = dump_list(to_show);  // get some help from the other version.
+    integer len = llStringLength(text);
+    integer i;
+    for (i = 0; i < len; i += MAX_CHAT_LINE) {
+        integer last_bit = i + MAX_CHAT_LINE - 1;
+        if (last_bit >= len) last_bit = len - 1;
+        string next_line = llGetSubString(text, i, last_bit);
+        llWhisper(0, next_line);
+    }
+}
+
+// returns a printable form of the list.
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = 0; i < len; i++) {
+        string next_line = llList2String(to_show, i);
+        if (find_substring(next_line, " ") >= 0) {
+            // this guy has a space in it, so quote it.
+            next_line = "\"" + next_line + "\"";
+        }
+        text = text + next_line;
+        if (i < len - 1) text = text + " ";
+    }
+    return text;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+// no huffotronic trap state for startup, because this script will actually
+// run (and is expected) inside a huffotronic updater object.
+
+default
+{
+    state_entry()
+    {
+        auto_retire();  // only allow the most recent revision.
+        initialize();
+        state awaiting_commands;
+    }
+}
+
+state awaiting_commands
+{
+    state_entry()
+    {
+        if (DEBUGGING) log_it("<awaiting_commands>");
+        careful_crankup();  // we always start by getting everyone running.
+        current_server = NULL_KEY;  // forget previous server.
+        listen_for_orders(FALSE);
+        inventory_request_channel = 0;  // no inventory request channel either.
+        update_channel = 0;  // no channel currently.
+        updates_needed = [];  // we know of no needs right now.
+        known_script_dependencies = [];  // no deps either.
+    }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message))
+            state establish_private_channel;
+    }
+}
+
+state establish_private_channel
+{
+    state_entry()
+    {
+        if (DEBUGGING) log_it("<establish_private_channel>");
+        llListen(update_channel, "", current_server, "");
+        listen_for_orders(TRUE);
+        if (inventory_request_channel)
+            llSay(inventory_request_channel, REQUEST_INVENTORY_PREFIX + (string)update_channel);
+        else
+            llSay(OLD_REQUEST_INVENTORY_CHANNEL, REQUEST_INVENTORY_PREFIX + (string)update_channel);
+        llSetTimerEvent(MAXIMUM_UPDATE_TIME_ALLOWED);
+    }
+
+    state_exit() { llSetTimerEvent(0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message)) {
+            // ready for a state change, but what kind?
+            if (llGetListLength(updates_needed)) {
+//log_it("have a list of updates now.");
+                state performing_update;
+            } else {
+//log_it("no updates needed in list, going back");
+                state awaiting_commands;
+            }
+        }
+    }
+    
+    timer() {
+        if (DEBUGGING) {
+            log_it("timed out establishing channel with server " + (string)inventory_request_channel);
+        }
+        whack_updater_record(current_server);
+        state awaiting_commands;
+    }
+
+    on_rez(integer parm) { state default; }
+}
+
+state performing_update
+{
+    state_entry()
+    {
+        // must re-listen after a state change.
+        llListen(update_channel, "", current_server, "");
+        listen_for_orders(TRUE);
+        if (DEBUGGING) log_it("<performing_update>");
+        llSetTimerEvent(UPDATE_TIMER_INTERVAL);
+        update_start_time = llGetUnixTime();
+    }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message)) {
+            // normal finish of update process.
+            state awaiting_commands;
+        }
+    }
+
+    timer() {
+        if (llGetListLength(updates_needed) == 0) {
+//log_it("nothing to update, leaving perform state.");
+            state awaiting_commands;  // we've got nothing to do.
+        } else {
+            // see if all our requested scripts are there yet; if not, we're not done updating.
+            integer ready = check_on_update_presence();
+            if (ready) {
+                if (DEBUGGING) log_it("reporting scripts are current.");
+                llSay(update_channel, SCRIPTS_ARE_CURRENT);
+            }
+        }
+        if (llAbs(update_start_time - llGetUnixTime()) >= MAXIMUM_UPDATE_TIME_ALLOWED) {
+            if (DEBUGGING) { log_it("timeout during update process with server " + (string)inventory_request_channel); }
+            whack_updater_record(current_server);
+            state awaiting_commands;
+        }
+    }
+
+    on_rez(integer parm) { state default; }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/huff-update_client_v20.1.txt b/huffware/huffotronic_tools_n_testers_v6.1/huff-update_client_v20.1.txt
deleted file mode 100755 (executable)
index 4a458bb..0000000
+++ /dev/null
@@ -1,826 +0,0 @@
-
-// huffware script: huff-update client, by fred huffhines.
-//
-// this script is the client side of the update process.  it should reside in an object that
-// has scripts which should be automatically updated.  it will listen for announcements by
-// an update server and communicate with the server to ensure that all of its scripts are
-// the most up to date available with the server.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-integer DEBUGGING = FALSE;  // if TRUE, the script will output status information.
-
-integer SERVER_IGNORE_TIME = 1200;  // number of seconds between performing an upgrade with the same server.
-
-integer MAXIMUM_UPDATE_TIME_ALLOWED = 140;  // we allow one upgrade process to take this long overall.
-
-integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
-integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
-
-string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
-string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
-string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
-string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
-string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
-string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
-string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
-string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
-string DONE_UPDATING                = "#finito#";  // the client is done updating.
-string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
-
-float UPDATE_TIMER_INTERVAL = 2.0;  // interval between checks on our update status.
-
-integer UPDATER_SCRIPT_PIN = -1231008;  // the hook for our scripts to be modified.
-
-///float BUSY_SERVER_PAUSE_TIME = 38.0;  // num seconds to delay when server says it's too busy.
-
-string UPDATER_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-
-string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
-string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
-
-integer MAXIMUM_SERVERS_TRACKED = 32;
-    // we will listen to this many servers before we decide to remove one.
-
-string CONTINUANCE_MARKER = "...";
-    // a string sent when the update list is too long and needs to be continued in another chat.
-
-string SERVER_SCRIPT = "a huffotronic update server";
-    // the prefix of our server script that hands out updates.
-
-// global variables...
-
-integer inventory_request_channel;  // used for newer version servers to cut down cross chatter.
-list updaters_heard;  // the update servers we've heard from recently.
-list last_interactions;  // times of the last update process engaged with the updater.
-integer update_channel;  // current channel for interaction with specific server.
-key current_server;  // the updater that is active right now, if any.
-integer update_start_time;  // when the last update process began.
-list updates_needed;  // stores the set of scripts that are in need of an update.
-list known_script_dependencies;  // stores the list of dependency info.
-
-careful_crankup()
-{
-    knock_around_other_scripts(TRUE);
-    // clean out the older items and scripts.  we do this after getting everyone running
-    // since we might be whacking ourselves.
-    destroy_older_versions();
-}
-
-// reset our variables.
-initialize()
-{
-    updaters_heard = [];
-    last_interactions = [];
-    inventory_request_channel = 0;
-    update_channel = 0;
-    current_server = NULL_KEY;
-    llSetTimerEvent(0.0);
-    llSetRemoteScriptAccessPin(UPDATER_SCRIPT_PIN);
-    // a new enhancements; tells the server that this guy has finished an update cycle.  this
-    // only comes into play when the updater script itself has just been updated, but it's
-    // nice for the server to avoid claiming erroneous timeouts occurred.
-    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
-    llSleep(0.4);  // snooze and repeat to overcome occasionally lossy chats.
-    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
-}
-
-whack_updater_record(key id)
-{
-    integer prev_indy = find_in_list(updaters_heard, id);
-    if (prev_indy < 0) return;  // not there.
-    updaters_heard = chop_list(updaters_heard, 0, prev_indy - 1)
-            + chop_list(updaters_heard, prev_indy + 1, llGetListLength(updaters_heard) - 1);
-    last_interactions = chop_list(last_interactions, 0, prev_indy - 1)
-            + chop_list(last_interactions, prev_indy + 1, llGetListLength(last_interactions) - 1);
-}
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        if (DEBUGGING)
-            log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-    // thirdly, try to clean out the notecards.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
-}
-
-// sets the object to be listening for update info.
-// if "just_owner" is true, then we will not listen on the general announcement channel.
-listen_for_orders(integer just_owner)
-{
-    if (!just_owner) {
-        // try to hear an update being announced.
-        llListen(UPDATE_ANNOUNCEMENT_CHANNEL, "", NULL_KEY, "");
-    }
-
-    // super secret owner controls.
-    llListen(0, "", llGetOwner(), "");
-}
-
-// returns true if this object is a huffotronic updater of some sort.
-integer inside_of_updater()
-{
-    return find_substring(llGetObjectName(), "huffotronic") >= 0;
-}
-
-// returns true if a script is a version of our update server.
-integer matches_server_script(string to_check)
-{
-    return is_prefix(to_check, SERVER_SCRIPT);
-}
-
-// stops all the scripts besides this one.
-knock_around_other_scripts(integer running_state)
-{
-    integer insider = inside_of_updater();
-    if (running_state == TRUE) {
-        // make sure we crank up the scripts that are new first.  we want to reset them
-        // as well, which we don't want to do for any existing scripts.
-        integer crank_indy;
-        for (crank_indy = 0; crank_indy < llGetListLength(updates_needed); crank_indy++) {
-            string crankee = llList2String(updates_needed, crank_indy);
-            if (find_in_inventory(crankee, INVENTORY_SCRIPT, TRUE) >= 0) {
-                if (!insider || matches_server_script(crankee)) {
-                    // allow it to run again.
-                    llSetScriptState(crankee, TRUE);
-                    // reset it, to make sure it starts at the top.
-                    llResetOtherScript(crankee);
-                }
-            }
-        }
-    }
-
-    integer indy;
-    string self_script = llGetScriptName();
-    // we set all other scripts to the running state requested.
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if ( (curr_script != self_script)
-            && (!insider || matches_server_script(curr_script)) ) {
-            // this one seems ripe for being set to the state requested.
-            llSetScriptState(curr_script, running_state);
-        }
-    }
-}
-
-// a random channel for the interaction with the server.
-integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
-
-// make sure that any dependencies for the script with "basename" are added to the list
-// of requests we make during an update.
-list add_dependencies(string basename)
-{
-    list to_return;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(known_script_dependencies); indy++) {
-        list deps = llParseString2List(llList2String(known_script_dependencies, indy),
-            [ITEM_LIST_SEPARATOR], []);
-//log_it("base=" + llList2String(dep, 0) + " lastver=" + llList2String(dep, 1) + " newdep=" + llList2String(dep, 2));
-        if (basename == llList2String(deps, 0)) {
-            // first off, is this item with new dependencies actually present?
-            integer where = find_in_inventory(basename, INVENTORY_SCRIPT, FALSE);
-            if (where >= 0) {
-                // we do use the script with deps, but is the dependent item really missing?
-                where = find_in_inventory(llList2String(deps, 1), INVENTORY_SCRIPT, FALSE);
-                if (where < 0) {
-                    // we found a dependency match for this script, so we'll ask for the missing item.
-                    if (DEBUGGING)
-                        log_it("missing dep: " + llList2String(deps, 1));
-                    to_return += [ llList2String(deps, 1) ];
-                }
-            }
-        }
-    }
-    return to_return;
-}
-
-// complains if memory seems to be getting tight.
-test_memory()
-{
-    if (llGetFreeMemory() < 4096)
-        log_it("mem_free = " + (string)llGetFreeMemory());
-}
-
-// starts an update given a list of scripts that the server has available, encoded as
-// a string in the "encoded_list".
-integer initiate_update(string encoded_list)
-{
-    list scripts_avail = llParseString2List(encoded_list, [UPDATER_PARM_SEPARATOR], []);
-    integer continue_listening_for_scripts = FALSE;
-      // if true, we aren't done hearing about available scripts yet.
-    encoded_list = "";
-    // figure out which scripts we need by comparing the list available from the server
-    // against our current inventory.  we only want scripts with newer version numbers.
-    integer sindy;
-    for (sindy = 0; sindy < llGetListLength(scripts_avail); sindy++) {
-        string curr = llList2String(scripts_avail, sindy);
-        if (curr == CONTINUANCE_MARKER) {
-            // this is a special continuation signal.  we need to hear the rest of the list.
-            continue_listening_for_scripts = TRUE;
-        } else if (is_prefix(curr, SCRIPT_DEPENDENCY_MARK)) {
-            // we've found a dependency item.
-            known_script_dependencies += [ llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1) ];
-//log_it("script dep: " + llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1));
-        } else {
-            list split = compute_basename_and_version(curr);
-            if (llGetListLength(split) == 2) {
-                string basename = llList2String(split, 0);
-                string version = llList2String(split, 1);
-                split = [];
-                integer oy_indy;
-//replace common code with func.
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_OBJECT); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_OBJECT, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-//                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-//                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_NOTECARD); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_NOTECARD, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_SCRIPT); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_SCRIPT, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                updates_needed += add_dependencies(basename);
-            }
-        }
-    }
-    // we skip the next step if we're still waiting to hear about more.
-    if (continue_listening_for_scripts) {
-//log_it("still listening for more updates...");
-        return FALSE;
-    }
-    if (llGetListLength(updates_needed)) {
-//log_it("update chan=" + (string)update_channel);
-        llSay(update_channel, REQUEST_SCRIPT_UPDATE);
-        if (DEBUGGING) {
-            log_it("told server " + (string)inventory_request_channel + " that i need updating.");
-        }
-    } else {
-        if (DEBUGGING) {
-            log_it("told server " + (string)inventory_request_channel + " that i am done updating.");
-        }
-        llSay(update_channel, DONE_UPDATING);
-    }
-    return TRUE;
-}    
-
-// this alerts the server to our most desired scripts.
-tell_server_our_wish_list()
-{
-    llSay(update_channel, READY_TO_UPDATE + wrap_parameters(updates_needed));
-}
-
-// checks whether all of the updates needed are present yet.
-integer check_on_update_presence()
-{
-    integer indy;
-    for (indy = 0; indy < llGetListLength(updates_needed); indy++) {
-        integer found = find_in_inventory(llList2String(updates_needed, indy), INVENTORY_ALL, TRUE);
-        // any single missing guy means they aren't up to date yet.
-        if (found < 0) {
-            if (DEBUGGING) log_it(llList2String(updates_needed, indy) + " not seen as updated yet.");
-            return FALSE;
-        }
-    }
-    // nothing was detected as missing anymore.
-    return TRUE;
-}
-
-// respond to spoken commands from the server.
-integer process_update_news(integer channel, string name, key id, string message)
-{
-    if (!channel) {
-        // this is a command.
-        if (message == "ureset") {
-            llResetScript();  // start over.
-        }
-        if (message == "ushow") {
-            integer sindy;
-            integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
-            list script_list = [ "scripts--" ];  // first item is just a header.
-            for (sindy = 0; sindy < script_count; sindy++) {
-                script_list += [ llGetInventoryName(INVENTORY_SCRIPT, sindy) ];
-            }
-            dump_list_to_log(script_list);
-        }
-        return FALSE;  // nothing to do here.
-    }
-    if (!update_channel && (channel == UPDATE_ANNOUNCEMENT_CHANNEL)) {
-/* never seen.        if (id == llGetKey()) {
-if (DEBUGGING) log_it("ignoring update from self.");            
-            return FALSE;  // ack, that's our very object.
-        }
-*/
-        if (llStringLength(message) > llStringLength(UPDATE_ANNOUNCEMENT_PREFIX)) {
-            // this is a new style update message.  we can set a different request channel.
-            string just_chan = llDeleteSubString(message, 0, llStringLength(UPDATE_ANNOUNCEMENT_PREFIX) - 1);
-            inventory_request_channel = (integer)just_chan;
-        }
-        integer prev_indy = find_in_list(updaters_heard, id);
-        // find the talker in our list.
-        if (prev_indy >= 0) {
-            // that guy was already heard from.  check when last interacted.
-            integer last_heard = llList2Integer(last_interactions, prev_indy);
-            if (llAbs(llGetUnixTime() - last_heard) < SERVER_IGNORE_TIME) {
-                return FALSE;  // not time to update with this guy again yet.
-            }
-//            if (DEBUGGING) { log_it("started listening again to server " + (string)id); }
-            // make sure we think of this as a new updater now.
-            whack_updater_record(id);
-        }
-
-        if (DEBUGGING) { log_it("heard server " + (string)inventory_request_channel + "'s announcement."); }
-        // record our new server.
-        current_server = id;
-        // make a random pause so not all updaters try to crank up at same time.
-        llSleep(randomize_within_range(2.8, 18.2, FALSE));
-
-        if (llGetListLength(updaters_heard) > MAXIMUM_SERVERS_TRACKED) {
-            // oops, this is not good.  we have too many servers now.
-//hmmm: room for improvement here by tossing out the server that is oldest.
-            updaters_heard = llDeleteSubList(updaters_heard, 0, 0);
-            last_interactions = llDeleteSubList(last_interactions, 0, 0);
-        }
-        
-        // add the talker to our list.
-        updaters_heard += id;
-        last_interactions += llGetUnixTime();
-    
-        // begin the update interaction with this guy.
-        update_channel = random_channel();
-        return TRUE;
-    }
-    if (update_channel && (channel == update_channel) ) {
-        if (is_prefix(message, REPORT_AVAILABLE_SCRIPTS)) {
-            // tasty, this is a list of scripts that can be had.
-            message = llDeleteSubString(message, 0, llStringLength(REPORT_AVAILABLE_SCRIPTS) - 1);
-            if (message == BUSY_BUSY) {
-                // server has signified that it's too busy (or its owner is a moron) because it is
-                // claiming it has no scripts at all.
-                if (DEBUGGING) {
-                    log_it("server " + (string)inventory_request_channel + " is too busy to update us now.");
-                }
-                // make it seem like we need to do this one again sooner than normal.
-                whack_updater_record(id);
-                // busy server means move no further forward.
-                return FALSE;
-            }
-            return initiate_update(message);
-        } else if (is_prefix(message, SHUT_THEM_DOWN)) {
-            if (DEBUGGING) { log_it("stopping other scripts."); }
-            knock_around_other_scripts(FALSE);
-            // now that we know for sure the server's ready to update us,
-            // we tell it what we need.
-            tell_server_our_wish_list();
-            return FALSE;
-        } else if (is_prefix(message, START_THEM_UP)) {
-            // let the server know that we've finished, for all intents and purposes.
-            llSay(update_channel, DONE_UPDATING);
-            // we pause a random bit first; we want to ensure we aren't swamping
-            // SL with our inventory loading.
-            llSleep(randomize_within_range(2.5, 8.2, FALSE));
-            if (DEBUGGING) { log_it("starting other scripts."); }
-            careful_crankup();
-            return TRUE;  // change state now.
-//        } else {
-//log_it("unknown command on update channel: " + message);
-        }
-    }
-    return FALSE;
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    llWhisper(0, llGetScriptName() + " [" + (string)debug_num + "] (" + (string)llGetFreeMemory() + ") " + to_say);
-}
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type, integer exact_match)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (exact_match && (llGetInventoryName(inv_type, inv) == name_to_find) )
-            return inv;
-        else if (!exact_match && is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-//////////////
-
-integer MAX_CHAT_LINE = 900;
-    // the most characters we'll try to say in one chat.
-
-dump_list_to_log(list to_show)
-{
-    string text = dump_list(to_show);  // get some help from the other version.
-    integer len = llStringLength(text);
-    integer i;
-    for (i = 0; i < len; i += MAX_CHAT_LINE) {
-        integer last_bit = i + MAX_CHAT_LINE - 1;
-        if (last_bit >= len) last_bit = len - 1;
-        string next_line = llGetSubString(text, i, last_bit);
-        llWhisper(0, next_line);
-    }
-}
-
-// returns a printable form of the list.
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = 0; i < len; i++) {
-        string next_line = llList2String(to_show, i);
-        if (find_substring(next_line, " ") >= 0) {
-            // this guy has a space in it, so quote it.
-            next_line = "\"" + next_line + "\"";
-        }
-        text = text + next_line;
-        if (i < len - 1) text = text + " ";
-    }
-    return text;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-// no huffotronic trap state for startup, because this script will actually
-// run (and is expected) inside a huffotronic updater object.
-
-default
-{
-    state_entry()
-    {
-        auto_retire();  // only allow the most recent revision.
-        initialize();
-        state awaiting_commands;
-    }
-}
-
-state awaiting_commands
-{
-    state_entry()
-    {
-        if (DEBUGGING) log_it("<awaiting_commands>");
-        careful_crankup();  // we always start by getting everyone running.
-        current_server = NULL_KEY;  // forget previous server.
-        listen_for_orders(FALSE);
-        inventory_request_channel = 0;  // no inventory request channel either.
-        update_channel = 0;  // no channel currently.
-        updates_needed = [];  // we know of no needs right now.
-        known_script_dependencies = [];  // no deps either.
-    }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message))
-            state establish_private_channel;
-    }
-}
-
-state establish_private_channel
-{
-    state_entry()
-    {
-        if (DEBUGGING) log_it("<establish_private_channel>");
-        llListen(update_channel, "", current_server, "");
-        listen_for_orders(TRUE);
-        if (inventory_request_channel)
-            llSay(inventory_request_channel, REQUEST_INVENTORY_PREFIX + (string)update_channel);
-        else
-            llSay(OLD_REQUEST_INVENTORY_CHANNEL, REQUEST_INVENTORY_PREFIX + (string)update_channel);
-        llSetTimerEvent(MAXIMUM_UPDATE_TIME_ALLOWED);
-    }
-
-    state_exit() { llSetTimerEvent(0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message)) {
-            // ready for a state change, but what kind?
-            if (llGetListLength(updates_needed)) {
-//log_it("have a list of updates now.");
-                state performing_update;
-            } else {
-//log_it("no updates needed in list, going back");
-                state awaiting_commands;
-            }
-        }
-    }
-    
-    timer() {
-        if (DEBUGGING) {
-            log_it("timed out establishing channel with server " + (string)inventory_request_channel);
-        }
-        whack_updater_record(current_server);
-        state awaiting_commands;
-    }
-
-    on_rez(integer parm) { state default; }
-}
-
-state performing_update
-{
-    state_entry()
-    {
-        // must re-listen after a state change.
-        llListen(update_channel, "", current_server, "");
-        listen_for_orders(TRUE);
-        if (DEBUGGING) log_it("<performing_update>");
-        llSetTimerEvent(UPDATE_TIMER_INTERVAL);
-        update_start_time = llGetUnixTime();
-    }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message)) {
-            // normal finish of update process.
-            state awaiting_commands;
-        }
-    }
-
-    timer() {
-        if (llGetListLength(updates_needed) == 0) {
-//log_it("nothing to update, leaving perform state.");
-            state awaiting_commands;  // we've got nothing to do.
-        } else {
-            // see if all our requested scripts are there yet; if not, we're not done updating.
-            integer ready = check_on_update_presence();
-            if (ready) {
-                if (DEBUGGING) log_it("reporting scripts are current.");
-                llSay(update_channel, SCRIPTS_ARE_CURRENT);
-            }
-        }
-        if (llAbs(update_start_time - llGetUnixTime()) >= MAXIMUM_UPDATE_TIME_ALLOWED) {
-            if (DEBUGGING) { log_it("timeout during update process with server " + (string)inventory_request_channel); }
-            whack_updater_record(current_server);
-            state awaiting_commands;
-        }
-    }
-
-    on_rez(integer parm) { state default; }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/invisiprim_v0.8.lsl b/huffware/huffotronic_tools_n_testers_v6.1/invisiprim_v0.8.lsl
new file mode 100755 (executable)
index 0000000..f44b36f
--- /dev/null
@@ -0,0 +1,151 @@
+
+// huffware script: invisiprim, by fred huffhines.
+//
+// a click on and off invisibility script.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        llSetTexture("e97cf410-8e61-7005-ec06-629eba4cd1fb", ALL_SIDES);
+            // This is one of the invisiprim textures.
+        llSetAlpha(1.0, ALL_SIDES);
+    }
+    touch(integer num) {
+        if (llDetectedKey(0) == llGetOwner()) {
+            // When touched, it will go back to a non-invisiprim.
+            state blank;
+        }
+    }
+}
+
+state blank
+{
+    state_entry() {
+        llSetTexture("4c1ce202-4196-f1c1-0409-367b3a71543e", ALL_SIDES);
+            // This is the 'Blank' texture
+        llSetAlpha(1.0, ALL_SIDES);
+    }
+    touch(integer num) {
+        if (llDetectedKey(0) == llGetOwner()) {
+            // When touched, it will go back to an invisiprim.
+            state default;
+        }
+    }
+    on_rez(integer parm) { llResetScript(); }
+}
+
+// attributions:
+//   invisiprim original version created by Opus Beck 9 aug 2007
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/invisiprim_v0.8.txt b/huffware/huffotronic_tools_n_testers_v6.1/invisiprim_v0.8.txt
deleted file mode 100755 (executable)
index f44b36f..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-
-// huffware script: invisiprim, by fred huffhines.
-//
-// a click on and off invisibility script.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        llSetTexture("e97cf410-8e61-7005-ec06-629eba4cd1fb", ALL_SIDES);
-            // This is one of the invisiprim textures.
-        llSetAlpha(1.0, ALL_SIDES);
-    }
-    touch(integer num) {
-        if (llDetectedKey(0) == llGetOwner()) {
-            // When touched, it will go back to a non-invisiprim.
-            state blank;
-        }
-    }
-}
-
-state blank
-{
-    state_entry() {
-        llSetTexture("4c1ce202-4196-f1c1-0409-367b3a71543e", ALL_SIDES);
-            // This is the 'Blank' texture
-        llSetAlpha(1.0, ALL_SIDES);
-    }
-    touch(integer num) {
-        if (llDetectedKey(0) == llGetOwner()) {
-            // When touched, it will go back to an invisiprim.
-            state default;
-        }
-    }
-    on_rez(integer parm) { llResetScript(); }
-}
-
-// attributions:
-//   invisiprim original version created by Opus Beck 9 aug 2007
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/link_reporter_v0.5.lsl b/huffware/huffotronic_tools_n_testers_v6.1/link_reporter_v0.5.lsl
new file mode 100755 (executable)
index 0000000..0e6fd66
--- /dev/null
@@ -0,0 +1,122 @@
+
+// huffware script: link reporter, by fred huffhines.
+//
+// a simple helper script that reports which link number this prim has.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        llSay(0, "This link is #" + (string)llGetLinkNumber());
+    }
+    
+    on_rez(integer parm) { llResetScript(); }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/link_reporter_v0.5.txt b/huffware/huffotronic_tools_n_testers_v6.1/link_reporter_v0.5.txt
deleted file mode 100755 (executable)
index 0e6fd66..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-
-// huffware script: link reporter, by fred huffhines.
-//
-// a simple helper script that reports which link number this prim has.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        llSay(0, "This link is #" + (string)llGetLinkNumber());
-    }
-    
-    on_rez(integer parm) { llResetScript(); }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/logic_system_main_v1.8.lsl b/huffware/huffotronic_tools_n_testers_v6.1/logic_system_main_v1.8.lsl
new file mode 100755 (executable)
index 0000000..aa0c30c
--- /dev/null
@@ -0,0 +1,561 @@
+
+// logic system master script
+// copyright john jamison, imagilearning?
+// created by xyz
+// modified by fred huffhines / chris koeritz.
+//
+//
+
+// defaults...
+vector TEXT_COLOR = <0.6, 0.84, 0.8>;  // label color.
+float RADARTIME = 10.0;  // how frequently radar fires.
+float RANGE = 50.0;  // range of the sensor sweeps.
+integer MAX_AVATAR_AWOLS = 5;
+    // number of times the avatar is allowed to be missed by sensor.
+    // we have seen some unreliability of sensors, so a single miss is not a definite problem.
+list RESET = ["Restart", "CANCEL"];  // used in a menu someplace?
+string Choicetimer = "2";  // how long they get to make their choice?
+
+// global variables...
+integer current_awols;
+key user = NULL_KEY;
+key lquery = NULL_KEY;
+list dialog;
+string CHOICE1;
+string CHOICE2;
+string CHOICE3;
+string CHOICE4;
+string CHOICE5;
+string CHOICE6;
+string CHOICE7;
+string CHOICE8;
+string CHOICE1TEXT;
+string CHOICE2TEXT;
+string CHOICE3TEXT;
+string CHOICE4TEXT;
+string CHOICE5TEXT;
+string CHOICE6TEXT;
+string CHOICE7TEXT;
+string CHOICE8TEXT;
+integer CHOICE1POINTS;
+integer CHOICE2POINTS;
+integer CHOICE3POINTS;
+integer CHOICE4POINTS;
+integer CHOICE5POINTS;
+integer CHOICE6POINTS;
+integer CHOICE7POINTS;
+integer CHOICE8POINTS;
+integer TotalScore;
+string DIALOG = " ";
+string CurrentNoteCard;
+string resettext = " ";
+list CHOICE;
+integer line = 0;
+integer eof = 0;
+integer CHANNEL;
+
+initialize()
+{
+    CHOICE = [ CHOICE1TEXT, CHOICE2TEXT, CHOICE3TEXT, CHOICE4TEXT ];
+    llSetText("[System Ready]", TEXT_COLOR, 1);
+    eof = 0;
+}
+
+// leave the current setup and completely restart the script.
+reboot(string reason)
+{
+llSay(0, "restarting now because " + reason);
+    llResetScript();
+}
+
+// starts looking for our registered user.
+start_sensor_sweeps()
+{
+    llSensorRemove();  // clear any existing sensor.
+//llSay(0, "sweeping for " + user + " aka " + llKey2Name(user));
+    llSensorRepeat("", user, AGENT, RANGE, 2 * PI, RADARTIME);  // look for our customer.
+}
+
+// what this did before made no sense...
+// but now it serves to reset the device if the avatar wandered off.
+handle_sensor(integer numDetected)
+{
+    integer proceed = FALSE;
+    integer i;
+    for (i = 0; i < numDetected; i++) {
+        if (llDetectedKey(i) == user) proceed = TRUE;
+    }
+    if (proceed) return;  // keep running like we were.
+    else reboot("we no longer saw our user here.");  // reboot, since we don't see our user.
+}
+
+// processes commands coming from other scripts or other parts of the object.
+handle_link_message(string str, key id)
+{
+    if (str == "user") {
+        user = id;
+        llSetText ("System in use by " + llKey2Name (id), TEXT_COLOR, 1);
+        CurrentNoteCard = llGetObjectDesc();
+        CHANNEL = llRound (llFrand (-394304));
+        llListen (CHANNEL, "", NULL_KEY, "");
+        start_sensor_sweeps();
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+}
+
+// handles notecard data as it is read.
+process_incoming_data(key query_id, string data)
+{
+    list split_data = llParseString2List (data, [":"], []);
+    string cmd = llToLower(llList2String(split_data, 0));
+
+//hmmm: terribly repetitive code here.  clean up, shorten.
+    if (cmd == "choicetimer") {
+        Choicetimer = llList2String (split_data, 1);
+    }
+    if (cmd == "chat") {
+        llSay(0, llList2String (split_data, 1));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "whisper") {
+        llWhisper(0, llList2String (split_data, 1));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "givenotecard") {
+        llGiveInventory (user, llList2String (split_data, 1));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "channelsay") {
+        llSay((integer) llList2String (split_data, 1), llList2String (split_data, 2));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "channelshout") {
+        llShout ((integer) llList2String (split_data, 1),
+                 llList2String (split_data, 2));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "channelwhisper") {
+        llSay((integer) llList2String (split_data, 1), llList2String (split_data, 2));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "resettext") {
+        resettext = llList2String (split_data, 1);
+
+    }
+    if (cmd == "end") {
+///        CurrentNoteCard = llGetObjectDesc();
+///        line = 0;
+        reboot("notecard said to end processing.");
+    }
+
+    if (cmd == "giveobject") {
+        llGiveInventory (user, llList2String (split_data, 1));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+///TALK TO VB AS THIS NEXT PART NEEDS A MEDIA RELAY FOR IT TO WORK
+    if (cmd == "videourl") {
+        if (llList2String (split_data, 3) != "") {
+            llParcelMediaCommandList ([PARCEL_MEDIA_COMMAND_URL,
+               llList2String (split_data, 1) + ":" +
+               llList2String (split_data, 2) + ":" +
+               llList2String (split_data, 3) +
+               llList2String (split_data, 4)]);
+            line++;
+            lquery = llGetNotecardLine (CurrentNoteCard, line);
+        }
+        else {
+            llParcelMediaCommandList ([PARCEL_MEDIA_COMMAND_URL,
+                llList2String (split_data, 1) + ":" +
+               llList2String (split_data, 2)]);
+            line++;
+            lquery = llGetNotecardLine (CurrentNoteCard, line);
+        }
+        //llSay(-840,llList2String(dat,1));
+        //llSay(-848,llList2String(dat,1));
+    }
+    if (cmd == "mediatexture") {
+        llParcelMediaCommandList ([PARCEL_MEDIA_COMMAND_TEXTURE,
+                                   (key) llList2String (split_data, 1)]);
+        //llSay(-849,llList2String(dat,1));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "sleep") {
+        llSleep (llList2Float (split_data, 1));
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "audiourl") {
+llSay(0, "got to audio url");
+        if (llList2String (split_data, 3) != "") {
+            llSetParcelMusicURL (llList2String (split_data, 1) + ":" +
+                llList2String (split_data, 2) + ":" +
+                llList2String (split_data, 3) + llList2String (split_data, 4));
+            line++;
+            lquery = llGetNotecardLine (CurrentNoteCard, line);
+        }
+
+        else {
+            llSetParcelMusicURL (llList2String (split_data, 1) + ":" +
+                llList2String (split_data, 2));
+            line++;
+            lquery = llGetNotecardLine (CurrentNoteCard, line);
+        }
+        //llSay(-840,llList2String(dat,1));
+    }
+    //THIS IS OPTION A//
+    if (cmd == "weburl") {
+        llLoadURL (user, llList2String (split_data, 1),
+                   llList2String (split_data, 2) + llList2String (split_data,
+                                                            3) +
+                   llList2String (split_data, 4));
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+
+
+    if (cmd == "dialog") {
+        DIALOG = llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice1") {
+        CHOICE1TEXT = llList2String (split_data, 1);
+        CHOICE1 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+
+    }
+    if (cmd == "choice2") {
+        CHOICE2TEXT = llList2String (split_data, 1);
+        CHOICE2 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice3") {
+        CHOICE3TEXT = llList2String (split_data, 1);
+        CHOICE3 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice4") {
+        CHOICE4TEXT = llList2String (split_data, 1);
+        CHOICE4 = llList2String (split_data, 2);
+
+        dialog = dialog +[llList2String (split_data, 1)];
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice5") {
+        CHOICE5TEXT = llList2String (split_data, 1);
+        CHOICE5 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+
+    }
+    if (cmd == "choice6") {
+        CHOICE6TEXT = llList2String (split_data, 1);
+        CHOICE6 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+
+    }
+
+    if (cmd == "choice7") {
+        CHOICE7TEXT = llList2String (split_data, 1);
+        CHOICE7 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+
+    }
+
+    if (cmd == "choice8") {
+        CHOICE8TEXT = llList2String (split_data, 1);
+        CHOICE8 = llList2String (split_data, 2);
+        dialog = dialog +[llList2String (split_data, 1)];
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+
+    }
+
+    if (cmd == "choice1points") {
+        CHOICE1POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+
+    }
+
+    if (cmd == "choice2points") {
+        CHOICE2POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice3points") {
+        CHOICE3POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice4points") {
+        CHOICE4POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice5points") {
+        CHOICE5POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice6points") {
+        CHOICE6POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice7points") {
+        CHOICE7POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "choice8points") {
+        CHOICE8POINTS = (integer) llList2String (split_data, 1);
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "email") {
+        llEmail (llList2String (split_data, 1),
+                 llKey2Name (user) + " Scored " + (string) TotalScore +
+                 " On " + llGetObjectDesc (),
+                 llKey2Name (user) + " Scored " + (string) TotalScore +
+                 " On " + llGetObjectDesc () + "Score As Of " +
+                 CurrentNoteCard);
+
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (cmd == "imuser") {
+        llInstantMessage (user, llList2String (split_data, 1));
+    }
+
+    if (cmd == "im") {
+        llInstantMessage (llList2String (split_data, 1), llList2String (split_data, 2));
+    }
+    if (cmd == "deadusertime") {
+        RADARTIME = (integer) llList2String (split_data, 1);
+    }
+
+    if (cmd == "deadrange") {
+        RANGE = (integer) llList2String (split_data, 1);
+        start_sensor_sweeps();
+    }
+
+    if (cmd == "finalscore") {
+        llSay (0,
+               "You Scored " + (string) TotalScore + "/" +
+               llList2String (split_data, 1));
+    }
+    if (cmd == "playsounduuid") {
+        llPreloadSound (llList2String (split_data, 1));
+        llPlaySound (llList2String (split_data, 1),
+                     (integer) llList2String (split_data, 2));
+    }
+
+    if (cmd == "debug") {
+        llSay (2147483647,
+               "System Debug Info follows " + "/n " +
+               (string) "key user = " + (string) user +
+               (string) " key lquery = " + (string) lquery +
+               (string) " integer DEADTIME = " + (string) RADARTIME +
+               "string CHOICE1 = " + CHOICE1 + "string CHOICE2 = " +
+               CHOICE2 + "string CHOICE3 = " + CHOICE3 +
+               "string CHOICE4 = " + CHOICE4 + "string CHOICE1TEXT = " +
+               CHOICE1TEXT + "string CHOICE2TEXT = " + CHOICE2TEXT +
+               "string CHOICE3TEXT= " + CHOICE3TEXT +
+               "string CHOICE4TEXT= " + CHOICE4TEXT +
+               "integer CHOICE1POINTS" + (string) CHOICE1POINTS +
+               "integer CHOICE2POINTS" + (string) CHOICE2POINTS +
+               "integer CHOICE3POINTS" + (string) CHOICE3POINTS +
+               "integer CHOICE4POINTS" + (string) CHOICE4POINTS +
+               "integer Choicetimer = " + (string) Choicetimer +
+               "integer TotalScore =" + (string) TotalScore +
+               "string DIOALOGE = " + DIALOG +
+               "string CurrentNoteCard = " + CurrentNoteCard +
+               "string resettext = " + resettext +
+               "list RESET = [Restart,CANCEL]" + "list CHOICE = " +
+               (string) CHOICE + "integer line = " + (string) line);
+
+    }
+
+    if (data == EOF) {
+        if (eof != 2 | eof == 1) {
+            eof = 2;
+            llSetTimerEvent ((float) Choicetimer);
+        }
+    } else {
+        line++;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+}
+
+// process what the device hears spoken nearby.
+hear_voices(integer channel, string name, key id, string message)
+{
+//hmmm: bunkum.  do this as a list.
+    if (message == CHOICE1TEXT) {
+        CurrentNoteCard = CHOICE1;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE1POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE2TEXT) {
+        CurrentNoteCard = CHOICE2;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE2POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE3TEXT) {
+        CurrentNoteCard = CHOICE3;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE3POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE4TEXT) {
+        CurrentNoteCard = CHOICE4;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE4POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE5TEXT) {
+        CurrentNoteCard = CHOICE5;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE5POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE6TEXT) {
+        CurrentNoteCard = CHOICE6;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE6POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE7TEXT) {
+        CurrentNoteCard = CHOICE7;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE7POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == CHOICE8TEXT) {
+        CurrentNoteCard = CHOICE8;
+        dialog =[];
+        eof = 0;
+        line = 0;
+        TotalScore = TotalScore + CHOICE8POINTS;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+    if (message == "Restart") {
+        eof = 0;
+        line = 0;
+        lquery = llGetNotecardLine (CurrentNoteCard, line);
+    }
+}
+
+//////////////
+
+// ensure stops running if kept in updater object.
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+// main state engine.
+state real_default
+{
+    state_entry () {
+        initialize();
+    }
+
+    on_rez (integer i) {
+        reboot("object just rezzed.");
+    }
+
+    no_sensor () {
+        current_awols++;
+//llSay(0, "sensor missed avatar.");
+        if (current_awols > MAX_AVATAR_AWOLS) {
+            reboot("avatar was missed by sensor sweep too many times.");
+        }
+    }
+
+    sensor (integer numDetected) {
+        current_awols = 0;
+//llSay(0, "sensor saw avatar.");
+        handle_sensor(numDetected);
+    }
+
+    link_message (integer sender_num, integer num, string str, key id) {
+        handle_link_message(str, id);
+    }
+
+    touch_start (integer total_number) {
+        integer i;
+        for (i = 0; i < total_number; i++) {
+            if (llDetectedKey(i) == user) {
+                llDialog (user, resettext, RESET, CHANNEL);
+                return;
+            }
+        }
+    }
+
+    listen (integer channel, string name, key id, string message) {
+        hear_voices(channel, name, id, message);
+    }
+
+    dataserver (key query_id, string data) {
+        process_incoming_data(query_id, data);
+    }
+
+    collision_start(integer total_number)
+    {
+        if (user == NULL_KEY) {
+//llSay(0, "sending startup link message.");
+            handle_link_message("user", llDetectedKey(0));
+        }
+    }
+
+    timer () {
+        llDialog (user, DIALOG, dialog, CHANNEL);
+        llSetTimerEvent (0);
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/logic_system_main_v1.8.txt b/huffware/huffotronic_tools_n_testers_v6.1/logic_system_main_v1.8.txt
deleted file mode 100755 (executable)
index aa0c30c..0000000
+++ /dev/null
@@ -1,561 +0,0 @@
-
-// logic system master script
-// copyright john jamison, imagilearning?
-// created by xyz
-// modified by fred huffhines / chris koeritz.
-//
-//
-
-// defaults...
-vector TEXT_COLOR = <0.6, 0.84, 0.8>;  // label color.
-float RADARTIME = 10.0;  // how frequently radar fires.
-float RANGE = 50.0;  // range of the sensor sweeps.
-integer MAX_AVATAR_AWOLS = 5;
-    // number of times the avatar is allowed to be missed by sensor.
-    // we have seen some unreliability of sensors, so a single miss is not a definite problem.
-list RESET = ["Restart", "CANCEL"];  // used in a menu someplace?
-string Choicetimer = "2";  // how long they get to make their choice?
-
-// global variables...
-integer current_awols;
-key user = NULL_KEY;
-key lquery = NULL_KEY;
-list dialog;
-string CHOICE1;
-string CHOICE2;
-string CHOICE3;
-string CHOICE4;
-string CHOICE5;
-string CHOICE6;
-string CHOICE7;
-string CHOICE8;
-string CHOICE1TEXT;
-string CHOICE2TEXT;
-string CHOICE3TEXT;
-string CHOICE4TEXT;
-string CHOICE5TEXT;
-string CHOICE6TEXT;
-string CHOICE7TEXT;
-string CHOICE8TEXT;
-integer CHOICE1POINTS;
-integer CHOICE2POINTS;
-integer CHOICE3POINTS;
-integer CHOICE4POINTS;
-integer CHOICE5POINTS;
-integer CHOICE6POINTS;
-integer CHOICE7POINTS;
-integer CHOICE8POINTS;
-integer TotalScore;
-string DIALOG = " ";
-string CurrentNoteCard;
-string resettext = " ";
-list CHOICE;
-integer line = 0;
-integer eof = 0;
-integer CHANNEL;
-
-initialize()
-{
-    CHOICE = [ CHOICE1TEXT, CHOICE2TEXT, CHOICE3TEXT, CHOICE4TEXT ];
-    llSetText("[System Ready]", TEXT_COLOR, 1);
-    eof = 0;
-}
-
-// leave the current setup and completely restart the script.
-reboot(string reason)
-{
-llSay(0, "restarting now because " + reason);
-    llResetScript();
-}
-
-// starts looking for our registered user.
-start_sensor_sweeps()
-{
-    llSensorRemove();  // clear any existing sensor.
-//llSay(0, "sweeping for " + user + " aka " + llKey2Name(user));
-    llSensorRepeat("", user, AGENT, RANGE, 2 * PI, RADARTIME);  // look for our customer.
-}
-
-// what this did before made no sense...
-// but now it serves to reset the device if the avatar wandered off.
-handle_sensor(integer numDetected)
-{
-    integer proceed = FALSE;
-    integer i;
-    for (i = 0; i < numDetected; i++) {
-        if (llDetectedKey(i) == user) proceed = TRUE;
-    }
-    if (proceed) return;  // keep running like we were.
-    else reboot("we no longer saw our user here.");  // reboot, since we don't see our user.
-}
-
-// processes commands coming from other scripts or other parts of the object.
-handle_link_message(string str, key id)
-{
-    if (str == "user") {
-        user = id;
-        llSetText ("System in use by " + llKey2Name (id), TEXT_COLOR, 1);
-        CurrentNoteCard = llGetObjectDesc();
-        CHANNEL = llRound (llFrand (-394304));
-        llListen (CHANNEL, "", NULL_KEY, "");
-        start_sensor_sweeps();
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-}
-
-// handles notecard data as it is read.
-process_incoming_data(key query_id, string data)
-{
-    list split_data = llParseString2List (data, [":"], []);
-    string cmd = llToLower(llList2String(split_data, 0));
-
-//hmmm: terribly repetitive code here.  clean up, shorten.
-    if (cmd == "choicetimer") {
-        Choicetimer = llList2String (split_data, 1);
-    }
-    if (cmd == "chat") {
-        llSay(0, llList2String (split_data, 1));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "whisper") {
-        llWhisper(0, llList2String (split_data, 1));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "givenotecard") {
-        llGiveInventory (user, llList2String (split_data, 1));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "channelsay") {
-        llSay((integer) llList2String (split_data, 1), llList2String (split_data, 2));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "channelshout") {
-        llShout ((integer) llList2String (split_data, 1),
-                 llList2String (split_data, 2));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "channelwhisper") {
-        llSay((integer) llList2String (split_data, 1), llList2String (split_data, 2));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "resettext") {
-        resettext = llList2String (split_data, 1);
-
-    }
-    if (cmd == "end") {
-///        CurrentNoteCard = llGetObjectDesc();
-///        line = 0;
-        reboot("notecard said to end processing.");
-    }
-
-    if (cmd == "giveobject") {
-        llGiveInventory (user, llList2String (split_data, 1));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-///TALK TO VB AS THIS NEXT PART NEEDS A MEDIA RELAY FOR IT TO WORK
-    if (cmd == "videourl") {
-        if (llList2String (split_data, 3) != "") {
-            llParcelMediaCommandList ([PARCEL_MEDIA_COMMAND_URL,
-               llList2String (split_data, 1) + ":" +
-               llList2String (split_data, 2) + ":" +
-               llList2String (split_data, 3) +
-               llList2String (split_data, 4)]);
-            line++;
-            lquery = llGetNotecardLine (CurrentNoteCard, line);
-        }
-        else {
-            llParcelMediaCommandList ([PARCEL_MEDIA_COMMAND_URL,
-                llList2String (split_data, 1) + ":" +
-               llList2String (split_data, 2)]);
-            line++;
-            lquery = llGetNotecardLine (CurrentNoteCard, line);
-        }
-        //llSay(-840,llList2String(dat,1));
-        //llSay(-848,llList2String(dat,1));
-    }
-    if (cmd == "mediatexture") {
-        llParcelMediaCommandList ([PARCEL_MEDIA_COMMAND_TEXTURE,
-                                   (key) llList2String (split_data, 1)]);
-        //llSay(-849,llList2String(dat,1));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "sleep") {
-        llSleep (llList2Float (split_data, 1));
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "audiourl") {
-llSay(0, "got to audio url");
-        if (llList2String (split_data, 3) != "") {
-            llSetParcelMusicURL (llList2String (split_data, 1) + ":" +
-                llList2String (split_data, 2) + ":" +
-                llList2String (split_data, 3) + llList2String (split_data, 4));
-            line++;
-            lquery = llGetNotecardLine (CurrentNoteCard, line);
-        }
-
-        else {
-            llSetParcelMusicURL (llList2String (split_data, 1) + ":" +
-                llList2String (split_data, 2));
-            line++;
-            lquery = llGetNotecardLine (CurrentNoteCard, line);
-        }
-        //llSay(-840,llList2String(dat,1));
-    }
-    //THIS IS OPTION A//
-    if (cmd == "weburl") {
-        llLoadURL (user, llList2String (split_data, 1),
-                   llList2String (split_data, 2) + llList2String (split_data,
-                                                            3) +
-                   llList2String (split_data, 4));
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-
-
-    if (cmd == "dialog") {
-        DIALOG = llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice1") {
-        CHOICE1TEXT = llList2String (split_data, 1);
-        CHOICE1 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-
-    }
-    if (cmd == "choice2") {
-        CHOICE2TEXT = llList2String (split_data, 1);
-        CHOICE2 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice3") {
-        CHOICE3TEXT = llList2String (split_data, 1);
-        CHOICE3 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice4") {
-        CHOICE4TEXT = llList2String (split_data, 1);
-        CHOICE4 = llList2String (split_data, 2);
-
-        dialog = dialog +[llList2String (split_data, 1)];
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice5") {
-        CHOICE5TEXT = llList2String (split_data, 1);
-        CHOICE5 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-
-    }
-    if (cmd == "choice6") {
-        CHOICE6TEXT = llList2String (split_data, 1);
-        CHOICE6 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-
-    }
-
-    if (cmd == "choice7") {
-        CHOICE7TEXT = llList2String (split_data, 1);
-        CHOICE7 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-
-    }
-
-    if (cmd == "choice8") {
-        CHOICE8TEXT = llList2String (split_data, 1);
-        CHOICE8 = llList2String (split_data, 2);
-        dialog = dialog +[llList2String (split_data, 1)];
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-
-    }
-
-    if (cmd == "choice1points") {
-        CHOICE1POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-
-    }
-
-    if (cmd == "choice2points") {
-        CHOICE2POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice3points") {
-        CHOICE3POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice4points") {
-        CHOICE4POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice5points") {
-        CHOICE5POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice6points") {
-        CHOICE6POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice7points") {
-        CHOICE7POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "choice8points") {
-        CHOICE8POINTS = (integer) llList2String (split_data, 1);
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "email") {
-        llEmail (llList2String (split_data, 1),
-                 llKey2Name (user) + " Scored " + (string) TotalScore +
-                 " On " + llGetObjectDesc (),
-                 llKey2Name (user) + " Scored " + (string) TotalScore +
-                 " On " + llGetObjectDesc () + "Score As Of " +
-                 CurrentNoteCard);
-
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (cmd == "imuser") {
-        llInstantMessage (user, llList2String (split_data, 1));
-    }
-
-    if (cmd == "im") {
-        llInstantMessage (llList2String (split_data, 1), llList2String (split_data, 2));
-    }
-    if (cmd == "deadusertime") {
-        RADARTIME = (integer) llList2String (split_data, 1);
-    }
-
-    if (cmd == "deadrange") {
-        RANGE = (integer) llList2String (split_data, 1);
-        start_sensor_sweeps();
-    }
-
-    if (cmd == "finalscore") {
-        llSay (0,
-               "You Scored " + (string) TotalScore + "/" +
-               llList2String (split_data, 1));
-    }
-    if (cmd == "playsounduuid") {
-        llPreloadSound (llList2String (split_data, 1));
-        llPlaySound (llList2String (split_data, 1),
-                     (integer) llList2String (split_data, 2));
-    }
-
-    if (cmd == "debug") {
-        llSay (2147483647,
-               "System Debug Info follows " + "/n " +
-               (string) "key user = " + (string) user +
-               (string) " key lquery = " + (string) lquery +
-               (string) " integer DEADTIME = " + (string) RADARTIME +
-               "string CHOICE1 = " + CHOICE1 + "string CHOICE2 = " +
-               CHOICE2 + "string CHOICE3 = " + CHOICE3 +
-               "string CHOICE4 = " + CHOICE4 + "string CHOICE1TEXT = " +
-               CHOICE1TEXT + "string CHOICE2TEXT = " + CHOICE2TEXT +
-               "string CHOICE3TEXT= " + CHOICE3TEXT +
-               "string CHOICE4TEXT= " + CHOICE4TEXT +
-               "integer CHOICE1POINTS" + (string) CHOICE1POINTS +
-               "integer CHOICE2POINTS" + (string) CHOICE2POINTS +
-               "integer CHOICE3POINTS" + (string) CHOICE3POINTS +
-               "integer CHOICE4POINTS" + (string) CHOICE4POINTS +
-               "integer Choicetimer = " + (string) Choicetimer +
-               "integer TotalScore =" + (string) TotalScore +
-               "string DIOALOGE = " + DIALOG +
-               "string CurrentNoteCard = " + CurrentNoteCard +
-               "string resettext = " + resettext +
-               "list RESET = [Restart,CANCEL]" + "list CHOICE = " +
-               (string) CHOICE + "integer line = " + (string) line);
-
-    }
-
-    if (data == EOF) {
-        if (eof != 2 | eof == 1) {
-            eof = 2;
-            llSetTimerEvent ((float) Choicetimer);
-        }
-    } else {
-        line++;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-}
-
-// process what the device hears spoken nearby.
-hear_voices(integer channel, string name, key id, string message)
-{
-//hmmm: bunkum.  do this as a list.
-    if (message == CHOICE1TEXT) {
-        CurrentNoteCard = CHOICE1;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE1POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE2TEXT) {
-        CurrentNoteCard = CHOICE2;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE2POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE3TEXT) {
-        CurrentNoteCard = CHOICE3;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE3POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE4TEXT) {
-        CurrentNoteCard = CHOICE4;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE4POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE5TEXT) {
-        CurrentNoteCard = CHOICE5;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE5POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE6TEXT) {
-        CurrentNoteCard = CHOICE6;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE6POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE7TEXT) {
-        CurrentNoteCard = CHOICE7;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE7POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == CHOICE8TEXT) {
-        CurrentNoteCard = CHOICE8;
-        dialog =[];
-        eof = 0;
-        line = 0;
-        TotalScore = TotalScore + CHOICE8POINTS;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-    if (message == "Restart") {
-        eof = 0;
-        line = 0;
-        lquery = llGetNotecardLine (CurrentNoteCard, line);
-    }
-}
-
-//////////////
-
-// ensure stops running if kept in updater object.
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-// main state engine.
-state real_default
-{
-    state_entry () {
-        initialize();
-    }
-
-    on_rez (integer i) {
-        reboot("object just rezzed.");
-    }
-
-    no_sensor () {
-        current_awols++;
-//llSay(0, "sensor missed avatar.");
-        if (current_awols > MAX_AVATAR_AWOLS) {
-            reboot("avatar was missed by sensor sweep too many times.");
-        }
-    }
-
-    sensor (integer numDetected) {
-        current_awols = 0;
-//llSay(0, "sensor saw avatar.");
-        handle_sensor(numDetected);
-    }
-
-    link_message (integer sender_num, integer num, string str, key id) {
-        handle_link_message(str, id);
-    }
-
-    touch_start (integer total_number) {
-        integer i;
-        for (i = 0; i < total_number; i++) {
-            if (llDetectedKey(i) == user) {
-                llDialog (user, resettext, RESET, CHANNEL);
-                return;
-            }
-        }
-    }
-
-    listen (integer channel, string name, key id, string message) {
-        hear_voices(channel, name, id, message);
-    }
-
-    dataserver (key query_id, string data) {
-        process_incoming_data(query_id, data);
-    }
-
-    collision_start(integer total_number)
-    {
-        if (user == NULL_KEY) {
-//llSay(0, "sending startup link message.");
-            handle_link_message("user", llDetectedKey(0));
-        }
-    }
-
-    timer () {
-        llDialog (user, DIALOG, dialog, CHANNEL);
-        llSetTimerEvent (0);
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/megaprim_v0.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/megaprim_v0.3.lsl
new file mode 100755 (executable)
index 0000000..c83303c
--- /dev/null
@@ -0,0 +1,33 @@
+
+// Megaprim! (auxiliary script if your viewer doesn't support custom size megaprims yet)
+// Fill in x, y, z with the values you need for your prim. They should be less or equal than 64.
+
+///////
+// defaults are not very mega-primish, and instead are nice for our huffotronic updaters.
+// --fred huffhines.
+///////
+
+float   x = .42;
+float   y = .42;
+float   z = .6;
+
+/*
+
+original author's note:
+
+Even if your viewer does not support yet the ability to create the new megas that are now available in the RC servers (the regions running the software for mesh, which you can check in Help: About in your viewer), a simple script, attached to this notice, will help you.
+
+Edit the script, change x, y, z with the values you want for the size, *up to 64 meters*, save it, and drop it into your prim. The script will do the work for you. These new megas will work in ANY sim when your rez them. Spread the love!
+
+Auryn Beorn
+
+*/
+
+default
+{
+    state_entry()
+    {
+        llSetPrimitiveParams([PRIM_SIZE, <x, y, z>]);
+//nooo...  we don't always want this.        llRemoveInventory(llGetScriptName());
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/megaprim_v0.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/megaprim_v0.3.txt
deleted file mode 100755 (executable)
index c83303c..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-
-// Megaprim! (auxiliary script if your viewer doesn't support custom size megaprims yet)
-// Fill in x, y, z with the values you need for your prim. They should be less or equal than 64.
-
-///////
-// defaults are not very mega-primish, and instead are nice for our huffotronic updaters.
-// --fred huffhines.
-///////
-
-float   x = .42;
-float   y = .42;
-float   z = .6;
-
-/*
-
-original author's note:
-
-Even if your viewer does not support yet the ability to create the new megas that are now available in the RC servers (the regions running the software for mesh, which you can check in Help: About in your viewer), a simple script, attached to this notice, will help you.
-
-Edit the script, change x, y, z with the values you want for the size, *up to 64 meters*, save it, and drop it into your prim. The script will do the work for you. These new megas will work in ANY sim when your rez them. Spread the love!
-
-Auryn Beorn
-
-*/
-
-default
-{
-    state_entry()
-    {
-        llSetPrimitiveParams([PRIM_SIZE, <x, y, z>]);
-//nooo...  we don't always want this.        llRemoveInventory(llGetScriptName());
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/mu_tester_v6.0.lsl b/huffware/huffotronic_tools_n_testers_v6.1/mu_tester_v6.0.lsl
new file mode 100755 (executable)
index 0000000..52b2291
--- /dev/null
@@ -0,0 +1,634 @@
+
+// huffware script: mu tester, by fred huffhines.
+//
+// a script that puts the set comparator library through its paces
+// while providing a textual method for creating and comparing sets.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// these are the commands a user can say:
+string DEFINE_WORD = "create";
+string DELETE_WORD = "delete";
+string LIST_WORD = "list";
+string GET_WORD = "get";
+string ADD_TO_WORD = "add";
+string CUT_FROM_WORD = "cut";
+string INTERSECT_WORD = "intersect";
+string UNION_WORD = "union";
+string DIFFERENCE_WORD = "differ";
+string MU_WORD = "mu";
+string CLEAR_ALL_WORD = "clearall";
+string RESET_WORD = "reset!";
+
+integer NOISY_OY = FALSE;
+  // produces more chatty logging when set to TRUE.  this is adjusted during
+  // startup to be off.
+
+// requires set comparator 2.8 or better.
+// API for set operations.
+//////////////
+integer SET_COMPARATOR_HUFFWARE_ID = 10020;
+    // a unique ID within the huffware system for this script.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+string DEFINE_SET_CMD = "#def-set";
+    // adds a new set or replaces existing one with same name.  first parm is name of set,
+    // second parm is a wrapped list of elements that should be in the set.  return value
+    // is a boolean for success.
+string REMOVE_SET_CMD = "#rm-set";
+    // trashes a named set.  first parm is the name.  returns a bool for success.
+string ADD_ELEMENTS_CMD = "#add-elem";
+    // adds more elements to an existing set.  first parm is the name, second is a wrapped
+    // list of new elements.  set must already exist.  returns a bool for success.
+string CUT_ELEMENTS_CMD = "#cut-elem";
+    // removes a set of elements from an existing set.  first parm is set name, second is
+    // wrapped list of elements to remove.  set must already exist.  returns bool.
+string INTERSECT_CMD = "#inter-set";
+    // reports the set of elements in the intersection of two sets.  first and second parm
+    // are the set names.  returns a wrapped list of elements that are common members of both sets.
+string UNION_CMD = "#union-set";
+    // returns the union of two named sets.  results sent similar to intersection.
+string DIFFERENCE_CMD = "#diff-set";
+    // returns the difference of set A (parm 1) minus set B (parm 2).  results are similar
+    // to intersection.
+string WHAT_MU_CMD = "#mu-set";
+    // returns one of the possibility values below to describe the relationship between
+    // two sets.
+string GET_SET_CMD = "#get-set";
+    // retrieves the contents of the set named in first parameter.
+string LIST_SET_NAMES_CMD = "#whichunz";
+    // retrieves the list of set names that exist.
+string CLEAR_ALL_CMD = "#clearall";
+    // throws out all set definitions.        
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// requires noteworthy library v8.4 or better.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be empty or missing.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or "bad_notecard" if none was found) and
+    // as subsequent elements an embedded list that was read from the notecard.  this
+    // necessarily limits the size of the notecards that we can read and return.
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+string BUSY_READING_INDICATOR = "busy_already";
+    // this return value indicates that the script is already in use by some other script.
+    // the calling script should try again later.
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+//
+//////////////
+
+string MU_SIGNATURE = "#mu";
+    // the notecard must begin with this as its first line for it to be
+    // recognized as our configuration card.
+
+// global variables...
+
+string global_notecard_name;  // name of our notecard in the object's inventory.
+integer response_code;  // set to uniquely identify the notecard read in progress.
+list global_config_list;  // a collection of configuration parameters from our notecard.
+integer global_config_index;  // allows wrap-around feature, which we don't use here.
+
+show_instructions()
+{
+    string c = ", ";  // speed of light.
+    string help_text = "\nThis object will operate on a collection of sets and understands the following commands:\n";
+    help_text += "  " + DEFINE_WORD + c + DELETE_WORD + c + CLEAR_ALL_WORD + c + ADD_TO_WORD + c
+        + CUT_FROM_WORD + c + INTERSECT_WORD + c + UNION_WORD + c + DIFFERENCE_WORD + c + GET_WORD + c
+        + LIST_WORD + c + RESET_WORD + c + "and " + MU_WORD + ".\n";
+    help_text += "Generally each command takes a set name or two, and sometimes a list of items.\n";
+    help_text += "If an item or set name has a space in it, surround it in quote characters.\n";
+    help_text += "For Example:\n";
+    help_text += "  " + DEFINE_WORD + " \"jed yo\" upsa dooba gorp : create a set named \"jed yo\" with three items.\n";
+    help_text += "  " + INTERSECT_WORD + " jed pfaltzgraff : returns the intersection of the two sets.\n";
+    help_text += "  " + ADD_TO_WORD + " foon a \"b c\" d e : adds four elements to the set \"foon\".\n";
+    help_text += "(Free Memory=" + (string)llGetFreeMemory() + ")\n";
+    llSay(0, help_text);
+}
+
+// makes a request of the set comparator.
+send_command(string msg, list parms)
+{ llMessageLinked(LINK_THIS, SET_COMPARATOR_HUFFWARE_ID, msg, wrap_parameters(parms)); }
+
+// processes verbal commands.
+hearing_some_voices(integer chan, string name, key id, string msg_in)
+{
+    // clean up the string before starting.
+    msg_in = llStringTrim(msg_in, STRING_TRIM);  // remove leading and trailing spaces.
+    msg_in = compress_spaces(msg_in);  // turn multiple spaces into a single one.
+    // separate out the separate words in what was said.
+    list members = parse_quoted_strings(msg_in);
+//log_it("got membs as: " + dump_list(members));
+    // break out the first few to make the below cases easier.
+    string first_word = llList2String(members, 0);
+    string second_word = llList2String(members, 1);
+    string third_word = llList2String(members, 2);
+
+    if (first_word == DEFINE_WORD) {
+        send_command(DEFINE_SET_CMD, llDeleteSubList(members, 0, 0));
+    } else if (first_word == DELETE_WORD) {
+        send_command(REMOVE_SET_CMD, [ second_word ]);
+    } else if (first_word == GET_WORD) {
+        send_command(GET_SET_CMD, [ second_word ]);
+    } else if (first_word == LIST_WORD) {
+        send_command(LIST_SET_NAMES_CMD, []);
+    } else if (first_word == ADD_TO_WORD) {
+        send_command(ADD_ELEMENTS_CMD, llDeleteSubList(members, 0, 0));
+    } else if (first_word == CUT_FROM_WORD) {
+        send_command(CUT_ELEMENTS_CMD, llDeleteSubList(members, 0, 0));
+    } else if (first_word == INTERSECT_WORD) {
+        send_command(INTERSECT_CMD, [ second_word, third_word ]);
+    } else if (first_word == UNION_WORD) {
+        send_command(UNION_CMD, [ second_word, third_word ]);
+    } else if (first_word == DIFFERENCE_WORD) {
+        send_command(DIFFERENCE_CMD, [ second_word, third_word ]);
+    } else if (first_word == MU_WORD) {
+        send_command(WHAT_MU_CMD, [ second_word, third_word ]);
+    } else if (first_word == CLEAR_ALL_WORD) {
+        send_command(CLEAR_ALL_CMD, []);
+    } else if (first_word == RESET_WORD) {
+        if (id != llGetOwner()) {
+            llSay(0, "Sorry, only the owner is allowed to reset this object.");
+        } else {
+            // tell the set manager to drop any contents also.
+            send_command(CLEAR_ALL_CMD, []);
+            llResetScript();
+        }
+    }
+    // we cannot have a catch-all here for if we didn't understand; that will always be
+    // getting hit whenever anyone talks nearby.
+}
+
+handle_link_message(integer sender, integer huff_id, string msg, key id)
+{
+    if (huff_id != SET_COMPARATOR_HUFFWARE_ID + REPLY_DISTANCE) {
+        handle_notecard_message(sender, huff_id, msg, id);
+        return;
+    }
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string to_show;  // what to tell the user.
+    if (llGetListLength(parms) == 1) {
+        // mono-syllabic responses.
+        string arf = llList2String(parms, 0);
+        if (arf == "0") {
+            to_show = "request failed";
+        } else if (arf == "1") {
+            to_show = "successful request";
+        } else if (msg != WHAT_MU_CMD) {
+            // don't know this one; assume it's a list.
+            to_show = "[ " + arf + " ]";
+        } else {
+            // otherwise we assume it's a well-known answer we should just emit.
+            to_show = arf;
+        }
+    } else {
+        to_show = "[ " + dump_list(parms) + " ]";
+    }
+    if (NOISY_OY) log_it("reply says: " + to_show);
+}
+
+// this function fires off a request to the noteworthy library via a link message.
+// noteworthy will look for a notecard with our particular signature in it and
+// if it finds one, it will read the configuration therein.  an empty string is
+// returned if noteworthy couldn't find anything.
+request_configuration()
+{
+    log_it("reading configuration...");
+    global_notecard_name = "";  // reset any previous card.
+    // try to find a notecard with our configuration.
+    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([MU_SIGNATURE, response_code]);
+    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+         parms_sent);
+}
+
+// processes link messages received from the noteworthy library.
+handle_notecard_message(integer which, integer num, string msg, key id)
+{
+    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
+            || (msg != READ_NOTECARD_COMMAND) )
+        return;  // not for us.
+    // process the result of reading the notecard.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string notecard_name = llList2String(parms, 0);
+    integer response_for = llList2Integer(parms, 1);
+    if (response_for != response_code) return;  // oops, this isn't for us.
+//log_it("read more from: " + notecard_name);
+    if (notecard_name == NOTECARD_READ_CONTINUATION) {
+        // just save these items for now.
+        global_config_list += llList2List(parms, 2, -1);
+    } else if (notecard_name != BAD_NOTECARD_INDICATOR) {
+        // a valid notecard has been found.
+        global_notecard_name = notecard_name;  // record its name for later use.
+        global_config_index = 0;  // we are starting over in the config list.
+        // snag all but the first two elements for our config now.
+        global_config_list += llList2List(parms, 2, -1);
+        process_ini_config();
+        log_it("now configured.");
+        llSetTimerEvent(6);  // pause a bit before turning chat back on.
+    } else {
+        // we hated the notecards we found, or there were none.
+        log_it("There seem to be no notecards with a first line of '"
+            + MU_SIGNATURE
+            + "', so no additional sets are defined.");
+    }
+}
+
+///////////////
+
+// eats a file with section names in square brackets, where every line defines a set element.
+process_ini_config()
+{
+    integer indy;
+    integer count = llGetListLength(global_config_list);
+    string section_name;
+
+    // iterate across the items in our configuration to look for ones that are not done yet.            
+    for (indy = global_config_index; indy < count; indy++) {
+        string line = llList2String(global_config_list, indy);
+        // search for a section beginning.
+        if (llGetSubString(line, 0, 0) == "[") {
+            // we found the start of a section name.  now read the contents.
+            indy++;  // skip section line.
+            section_name = llGetSubString(line, 1, -2);
+            if (NOISY_OY) log_it("set '" + section_name + "' is being defined.");
+        }
+        integer sec_indy;
+        for (sec_indy = indy; sec_indy < count; sec_indy++) {
+            // read the lines in the section.
+            line = llList2String(global_config_list, sec_indy);
+            if (llGetSubString(line, 0, 0) != "[") {
+                if (NOISY_OY) log_it(line);
+                hearing_some_voices(0, llGetScriptName(), llGetOwner(), line);
+                indy = sec_indy;  // track that we've passed this line.
+            } else {
+                // we're at the beginning of a new section now, so start processing its
+                // configuration in the outer loop.
+                indy = sec_indy - 1;  // set indy to proper beginning of section.
+                global_config_index = indy;  // remember where we had read to.
+                sec_indy = count + 3;  // skip remainder of inner loop.
+            }
+        }
+    }
+
+    global_config_index = 0;  // reset outer position if want to re-read.
+}
+
+//////////////
+// from hufflets:
+
+integer debug_num = 0;
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+//    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+    llSay(0, to_say);
+}
+
+// the string processing methods are not case sensitive.
+  
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (llGetInventoryName(inv_type, inv) == name_to_find)
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+// returns a printable form of the list.
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = 0; i < len; i++) {
+        string next_line = llList2String(to_show, i);
+        if (find_substring(next_line, " ") >= 0) {
+            // this guy has a space in it, so quote it.
+            next_line = "\"" + next_line + "\"";
+        }
+        text += next_line;
+        if (i < len - 1) text += " ";
+    }
+    return text;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+    return [ llStringTrim(x, STRING_TRIM), llStringTrim(y, STRING_TRIM) ];
+}
+
+// returns a non-empty string if "to_check" defines a value for "variable_name".
+// this must be in the form "X=Y", where X is the variable_name and Y is the value.
+string get_variable_value(string to_check, string variable_name)
+{
+    list x_y = separate_variable_definition(to_check);
+    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
+    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
+    return llList2String(x_y, 1);  // a match!
+}
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// extracts space separated elements from a string, and honors quoting of either
+// variety as long as the quotes come in pairs.  this enables the inclusion of
+// spaces in the elements of the set.  note that this function requires a well-formed
+// string where there are no multiple space characters in a row.
+list parse_quoted_strings(string to_parse)
+{
+    list to_return;  // will pile up what we find in the string.
+    integer quoting = FALSE;  // are we inside quotes?
+    string curr_quote = "";  // what is current quote char, if any?
+    string accum;  // accumulates parts of the current element.
+    // loop over the string and apply our rules.
+    integer i;
+    for (i = 0; i < llStringLength(to_parse); i++) {
+        string c = llGetSubString(to_parse, i, i);
+        if (!quoting && (c == " ")) {
+            // this space marks the end of a word.
+            if (llStringLength(accum) > 0) {
+//log_it("space adding to set: " + accum);
+                to_return += [ accum ];
+                accum = "";
+            }
+        } else if (quoting && (c == curr_quote)) {
+            quoting = FALSE;
+        } else if (!quoting && ( (c == "'") || (c == "\"") ) ) {
+            // we've started into quoting mode.
+            quoting = TRUE;
+            curr_quote = c;
+        } else {
+            // if no condition applies, just add this to the accumulator.
+            accum += c;
+        }
+    }
+    // add the last thing we accumulated.
+    if (llStringLength(accum) > 0) {
+//log_it("last add to set: " + accum);
+        to_return += [ accum ];
+    }
+    return to_return;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// takes any redundant space characters out of the string.
+string compress_spaces(string s)
+{
+    string to_return;
+    integer in_space = FALSE;
+    integer i;
+    for (i = 0; i < llStringLength(s); i++) {
+        string chunk = llGetSubString(s, i, i);
+        if (chunk == " ") {
+            if (in_space) {
+                // we're have already seen a space.  don't keep this too.
+                //continue;  no such keyword in lsl.
+            } else {
+                in_space = TRUE;
+                to_return += chunk;
+            }
+        } else {
+            // the current character was not a space, so just add it.
+            in_space = FALSE;
+            to_return += chunk;
+        }
+    }
+    return to_return;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end from hufflets.
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { 
+        auto_retire();
+        NOISY_OY = FALSE;
+        // reset our relevant variables.
+        global_notecard_name = "";
+        global_config_list = [];
+        global_config_index = 0;
+        // request that the noteworthy library start looking for our notecard.
+        request_configuration();
+        // listen for commands from people.
+        llListen(0, "", NULL_KEY, "");
+        NOISY_OY = FALSE;
+    }
+    
+    state_exit() { llSetTimerEvent(0.0); }
+
+    touch_start(integer total_number) { show_instructions(); }
+
+    listen(integer chan, string name, key id, string msg)
+    { hearing_some_voices(chan, name, id, msg); }
+
+    link_message(integer sender, integer num, string msg, key id) {
+        if ( (num != SET_COMPARATOR_HUFFWARE_ID + REPLY_DISTANCE)
+            && (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE) )
+            return;  // not for us.
+        handle_link_message(sender, num, msg, id);
+    }
+    
+    timer() {
+        NOISY_OY = TRUE;  // assume we can now chat with the user.  config is done hopefully.
+        llSetTimerEvent(0.0);  // turn off timer now.
+    }
+
+    on_rez(integer parm) { show_instructions(); state rerun; }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/mu_tester_v6.0.txt b/huffware/huffotronic_tools_n_testers_v6.1/mu_tester_v6.0.txt
deleted file mode 100755 (executable)
index 52b2291..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-
-// huffware script: mu tester, by fred huffhines.
-//
-// a script that puts the set comparator library through its paces
-// while providing a textual method for creating and comparing sets.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// these are the commands a user can say:
-string DEFINE_WORD = "create";
-string DELETE_WORD = "delete";
-string LIST_WORD = "list";
-string GET_WORD = "get";
-string ADD_TO_WORD = "add";
-string CUT_FROM_WORD = "cut";
-string INTERSECT_WORD = "intersect";
-string UNION_WORD = "union";
-string DIFFERENCE_WORD = "differ";
-string MU_WORD = "mu";
-string CLEAR_ALL_WORD = "clearall";
-string RESET_WORD = "reset!";
-
-integer NOISY_OY = FALSE;
-  // produces more chatty logging when set to TRUE.  this is adjusted during
-  // startup to be off.
-
-// requires set comparator 2.8 or better.
-// API for set operations.
-//////////////
-integer SET_COMPARATOR_HUFFWARE_ID = 10020;
-    // a unique ID within the huffware system for this script.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-string DEFINE_SET_CMD = "#def-set";
-    // adds a new set or replaces existing one with same name.  first parm is name of set,
-    // second parm is a wrapped list of elements that should be in the set.  return value
-    // is a boolean for success.
-string REMOVE_SET_CMD = "#rm-set";
-    // trashes a named set.  first parm is the name.  returns a bool for success.
-string ADD_ELEMENTS_CMD = "#add-elem";
-    // adds more elements to an existing set.  first parm is the name, second is a wrapped
-    // list of new elements.  set must already exist.  returns a bool for success.
-string CUT_ELEMENTS_CMD = "#cut-elem";
-    // removes a set of elements from an existing set.  first parm is set name, second is
-    // wrapped list of elements to remove.  set must already exist.  returns bool.
-string INTERSECT_CMD = "#inter-set";
-    // reports the set of elements in the intersection of two sets.  first and second parm
-    // are the set names.  returns a wrapped list of elements that are common members of both sets.
-string UNION_CMD = "#union-set";
-    // returns the union of two named sets.  results sent similar to intersection.
-string DIFFERENCE_CMD = "#diff-set";
-    // returns the difference of set A (parm 1) minus set B (parm 2).  results are similar
-    // to intersection.
-string WHAT_MU_CMD = "#mu-set";
-    // returns one of the possibility values below to describe the relationship between
-    // two sets.
-string GET_SET_CMD = "#get-set";
-    // retrieves the contents of the set named in first parameter.
-string LIST_SET_NAMES_CMD = "#whichunz";
-    // retrieves the list of set names that exist.
-string CLEAR_ALL_CMD = "#clearall";
-    // throws out all set definitions.        
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// requires noteworthy library v8.4 or better.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be empty or missing.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or "bad_notecard" if none was found) and
-    // as subsequent elements an embedded list that was read from the notecard.  this
-    // necessarily limits the size of the notecards that we can read and return.
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-string BUSY_READING_INDICATOR = "busy_already";
-    // this return value indicates that the script is already in use by some other script.
-    // the calling script should try again later.
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-//
-//////////////
-
-string MU_SIGNATURE = "#mu";
-    // the notecard must begin with this as its first line for it to be
-    // recognized as our configuration card.
-
-// global variables...
-
-string global_notecard_name;  // name of our notecard in the object's inventory.
-integer response_code;  // set to uniquely identify the notecard read in progress.
-list global_config_list;  // a collection of configuration parameters from our notecard.
-integer global_config_index;  // allows wrap-around feature, which we don't use here.
-
-show_instructions()
-{
-    string c = ", ";  // speed of light.
-    string help_text = "\nThis object will operate on a collection of sets and understands the following commands:\n";
-    help_text += "  " + DEFINE_WORD + c + DELETE_WORD + c + CLEAR_ALL_WORD + c + ADD_TO_WORD + c
-        + CUT_FROM_WORD + c + INTERSECT_WORD + c + UNION_WORD + c + DIFFERENCE_WORD + c + GET_WORD + c
-        + LIST_WORD + c + RESET_WORD + c + "and " + MU_WORD + ".\n";
-    help_text += "Generally each command takes a set name or two, and sometimes a list of items.\n";
-    help_text += "If an item or set name has a space in it, surround it in quote characters.\n";
-    help_text += "For Example:\n";
-    help_text += "  " + DEFINE_WORD + " \"jed yo\" upsa dooba gorp : create a set named \"jed yo\" with three items.\n";
-    help_text += "  " + INTERSECT_WORD + " jed pfaltzgraff : returns the intersection of the two sets.\n";
-    help_text += "  " + ADD_TO_WORD + " foon a \"b c\" d e : adds four elements to the set \"foon\".\n";
-    help_text += "(Free Memory=" + (string)llGetFreeMemory() + ")\n";
-    llSay(0, help_text);
-}
-
-// makes a request of the set comparator.
-send_command(string msg, list parms)
-{ llMessageLinked(LINK_THIS, SET_COMPARATOR_HUFFWARE_ID, msg, wrap_parameters(parms)); }
-
-// processes verbal commands.
-hearing_some_voices(integer chan, string name, key id, string msg_in)
-{
-    // clean up the string before starting.
-    msg_in = llStringTrim(msg_in, STRING_TRIM);  // remove leading and trailing spaces.
-    msg_in = compress_spaces(msg_in);  // turn multiple spaces into a single one.
-    // separate out the separate words in what was said.
-    list members = parse_quoted_strings(msg_in);
-//log_it("got membs as: " + dump_list(members));
-    // break out the first few to make the below cases easier.
-    string first_word = llList2String(members, 0);
-    string second_word = llList2String(members, 1);
-    string third_word = llList2String(members, 2);
-
-    if (first_word == DEFINE_WORD) {
-        send_command(DEFINE_SET_CMD, llDeleteSubList(members, 0, 0));
-    } else if (first_word == DELETE_WORD) {
-        send_command(REMOVE_SET_CMD, [ second_word ]);
-    } else if (first_word == GET_WORD) {
-        send_command(GET_SET_CMD, [ second_word ]);
-    } else if (first_word == LIST_WORD) {
-        send_command(LIST_SET_NAMES_CMD, []);
-    } else if (first_word == ADD_TO_WORD) {
-        send_command(ADD_ELEMENTS_CMD, llDeleteSubList(members, 0, 0));
-    } else if (first_word == CUT_FROM_WORD) {
-        send_command(CUT_ELEMENTS_CMD, llDeleteSubList(members, 0, 0));
-    } else if (first_word == INTERSECT_WORD) {
-        send_command(INTERSECT_CMD, [ second_word, third_word ]);
-    } else if (first_word == UNION_WORD) {
-        send_command(UNION_CMD, [ second_word, third_word ]);
-    } else if (first_word == DIFFERENCE_WORD) {
-        send_command(DIFFERENCE_CMD, [ second_word, third_word ]);
-    } else if (first_word == MU_WORD) {
-        send_command(WHAT_MU_CMD, [ second_word, third_word ]);
-    } else if (first_word == CLEAR_ALL_WORD) {
-        send_command(CLEAR_ALL_CMD, []);
-    } else if (first_word == RESET_WORD) {
-        if (id != llGetOwner()) {
-            llSay(0, "Sorry, only the owner is allowed to reset this object.");
-        } else {
-            // tell the set manager to drop any contents also.
-            send_command(CLEAR_ALL_CMD, []);
-            llResetScript();
-        }
-    }
-    // we cannot have a catch-all here for if we didn't understand; that will always be
-    // getting hit whenever anyone talks nearby.
-}
-
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-    if (huff_id != SET_COMPARATOR_HUFFWARE_ID + REPLY_DISTANCE) {
-        handle_notecard_message(sender, huff_id, msg, id);
-        return;
-    }
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string to_show;  // what to tell the user.
-    if (llGetListLength(parms) == 1) {
-        // mono-syllabic responses.
-        string arf = llList2String(parms, 0);
-        if (arf == "0") {
-            to_show = "request failed";
-        } else if (arf == "1") {
-            to_show = "successful request";
-        } else if (msg != WHAT_MU_CMD) {
-            // don't know this one; assume it's a list.
-            to_show = "[ " + arf + " ]";
-        } else {
-            // otherwise we assume it's a well-known answer we should just emit.
-            to_show = arf;
-        }
-    } else {
-        to_show = "[ " + dump_list(parms) + " ]";
-    }
-    if (NOISY_OY) log_it("reply says: " + to_show);
-}
-
-// this function fires off a request to the noteworthy library via a link message.
-// noteworthy will look for a notecard with our particular signature in it and
-// if it finds one, it will read the configuration therein.  an empty string is
-// returned if noteworthy couldn't find anything.
-request_configuration()
-{
-    log_it("reading configuration...");
-    global_notecard_name = "";  // reset any previous card.
-    // try to find a notecard with our configuration.
-    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([MU_SIGNATURE, response_code]);
-    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-         parms_sent);
-}
-
-// processes link messages received from the noteworthy library.
-handle_notecard_message(integer which, integer num, string msg, key id)
-{
-    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
-            || (msg != READ_NOTECARD_COMMAND) )
-        return;  // not for us.
-    // process the result of reading the notecard.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string notecard_name = llList2String(parms, 0);
-    integer response_for = llList2Integer(parms, 1);
-    if (response_for != response_code) return;  // oops, this isn't for us.
-//log_it("read more from: " + notecard_name);
-    if (notecard_name == NOTECARD_READ_CONTINUATION) {
-        // just save these items for now.
-        global_config_list += llList2List(parms, 2, -1);
-    } else if (notecard_name != BAD_NOTECARD_INDICATOR) {
-        // a valid notecard has been found.
-        global_notecard_name = notecard_name;  // record its name for later use.
-        global_config_index = 0;  // we are starting over in the config list.
-        // snag all but the first two elements for our config now.
-        global_config_list += llList2List(parms, 2, -1);
-        process_ini_config();
-        log_it("now configured.");
-        llSetTimerEvent(6);  // pause a bit before turning chat back on.
-    } else {
-        // we hated the notecards we found, or there were none.
-        log_it("There seem to be no notecards with a first line of '"
-            + MU_SIGNATURE
-            + "', so no additional sets are defined.");
-    }
-}
-
-///////////////
-
-// eats a file with section names in square brackets, where every line defines a set element.
-process_ini_config()
-{
-    integer indy;
-    integer count = llGetListLength(global_config_list);
-    string section_name;
-
-    // iterate across the items in our configuration to look for ones that are not done yet.            
-    for (indy = global_config_index; indy < count; indy++) {
-        string line = llList2String(global_config_list, indy);
-        // search for a section beginning.
-        if (llGetSubString(line, 0, 0) == "[") {
-            // we found the start of a section name.  now read the contents.
-            indy++;  // skip section line.
-            section_name = llGetSubString(line, 1, -2);
-            if (NOISY_OY) log_it("set '" + section_name + "' is being defined.");
-        }
-        integer sec_indy;
-        for (sec_indy = indy; sec_indy < count; sec_indy++) {
-            // read the lines in the section.
-            line = llList2String(global_config_list, sec_indy);
-            if (llGetSubString(line, 0, 0) != "[") {
-                if (NOISY_OY) log_it(line);
-                hearing_some_voices(0, llGetScriptName(), llGetOwner(), line);
-                indy = sec_indy;  // track that we've passed this line.
-            } else {
-                // we're at the beginning of a new section now, so start processing its
-                // configuration in the outer loop.
-                indy = sec_indy - 1;  // set indy to proper beginning of section.
-                global_config_index = indy;  // remember where we had read to.
-                sec_indy = count + 3;  // skip remainder of inner loop.
-            }
-        }
-    }
-
-    global_config_index = 0;  // reset outer position if want to re-read.
-}
-
-//////////////
-// from hufflets:
-
-integer debug_num = 0;
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-//    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-    llSay(0, to_say);
-}
-
-// the string processing methods are not case sensitive.
-  
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (llGetInventoryName(inv_type, inv) == name_to_find)
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-// returns a printable form of the list.
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = 0; i < len; i++) {
-        string next_line = llList2String(to_show, i);
-        if (find_substring(next_line, " ") >= 0) {
-            // this guy has a space in it, so quote it.
-            next_line = "\"" + next_line + "\"";
-        }
-        text += next_line;
-        if (i < len - 1) text += " ";
-    }
-    return text;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-    return [ llStringTrim(x, STRING_TRIM), llStringTrim(y, STRING_TRIM) ];
-}
-
-// returns a non-empty string if "to_check" defines a value for "variable_name".
-// this must be in the form "X=Y", where X is the variable_name and Y is the value.
-string get_variable_value(string to_check, string variable_name)
-{
-    list x_y = separate_variable_definition(to_check);
-    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
-    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
-    return llList2String(x_y, 1);  // a match!
-}
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// extracts space separated elements from a string, and honors quoting of either
-// variety as long as the quotes come in pairs.  this enables the inclusion of
-// spaces in the elements of the set.  note that this function requires a well-formed
-// string where there are no multiple space characters in a row.
-list parse_quoted_strings(string to_parse)
-{
-    list to_return;  // will pile up what we find in the string.
-    integer quoting = FALSE;  // are we inside quotes?
-    string curr_quote = "";  // what is current quote char, if any?
-    string accum;  // accumulates parts of the current element.
-    // loop over the string and apply our rules.
-    integer i;
-    for (i = 0; i < llStringLength(to_parse); i++) {
-        string c = llGetSubString(to_parse, i, i);
-        if (!quoting && (c == " ")) {
-            // this space marks the end of a word.
-            if (llStringLength(accum) > 0) {
-//log_it("space adding to set: " + accum);
-                to_return += [ accum ];
-                accum = "";
-            }
-        } else if (quoting && (c == curr_quote)) {
-            quoting = FALSE;
-        } else if (!quoting && ( (c == "'") || (c == "\"") ) ) {
-            // we've started into quoting mode.
-            quoting = TRUE;
-            curr_quote = c;
-        } else {
-            // if no condition applies, just add this to the accumulator.
-            accum += c;
-        }
-    }
-    // add the last thing we accumulated.
-    if (llStringLength(accum) > 0) {
-//log_it("last add to set: " + accum);
-        to_return += [ accum ];
-    }
-    return to_return;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// takes any redundant space characters out of the string.
-string compress_spaces(string s)
-{
-    string to_return;
-    integer in_space = FALSE;
-    integer i;
-    for (i = 0; i < llStringLength(s); i++) {
-        string chunk = llGetSubString(s, i, i);
-        if (chunk == " ") {
-            if (in_space) {
-                // we're have already seen a space.  don't keep this too.
-                //continue;  no such keyword in lsl.
-            } else {
-                in_space = TRUE;
-                to_return += chunk;
-            }
-        } else {
-            // the current character was not a space, so just add it.
-            in_space = FALSE;
-            to_return += chunk;
-        }
-    }
-    return to_return;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end from hufflets.
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { 
-        auto_retire();
-        NOISY_OY = FALSE;
-        // reset our relevant variables.
-        global_notecard_name = "";
-        global_config_list = [];
-        global_config_index = 0;
-        // request that the noteworthy library start looking for our notecard.
-        request_configuration();
-        // listen for commands from people.
-        llListen(0, "", NULL_KEY, "");
-        NOISY_OY = FALSE;
-    }
-    
-    state_exit() { llSetTimerEvent(0.0); }
-
-    touch_start(integer total_number) { show_instructions(); }
-
-    listen(integer chan, string name, key id, string msg)
-    { hearing_some_voices(chan, name, id, msg); }
-
-    link_message(integer sender, integer num, string msg, key id) {
-        if ( (num != SET_COMPARATOR_HUFFWARE_ID + REPLY_DISTANCE)
-            && (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE) )
-            return;  // not for us.
-        handle_link_message(sender, num, msg, id);
-    }
-    
-    timer() {
-        NOISY_OY = TRUE;  // assume we can now chat with the user.  config is done hopefully.
-        llSetTimerEvent(0.0);  // turn off timer now.
-    }
-
-    on_rez(integer parm) { show_instructions(); state rerun; }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/no_sitting_on_vendor_v1.0.lsl b/huffware/huffotronic_tools_n_testers_v6.1/no_sitting_on_vendor_v1.0.lsl
new file mode 100755 (executable)
index 0000000..485b57f
--- /dev/null
@@ -0,0 +1,137 @@
+
+// huffware script: no sitting on vendor, by fred huffhines.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// this message will be displayed when someone sits on the vendor.
+string AVATAR_MESSAGE = "You cannot sit here; I am a vendor, not a chair.  Please touch me for a notecard, or pay me to purchase the product.  Thanks!";
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();  // make sure newest addition is only version of script.
+        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);
+    }
+    
+    changed(integer change)
+    {
+        key id = llAvatarOnSitTarget();
+        if (change & CHANGED_LINK) {
+            if (id != NULL_KEY) {
+                llUnSit(id);
+                llDialog(id, AVATAR_MESSAGE, [], -981238);
+                    // we don't listen for the response.
+            }
+        }
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/no_sitting_on_vendor_v1.0.txt b/huffware/huffotronic_tools_n_testers_v6.1/no_sitting_on_vendor_v1.0.txt
deleted file mode 100755 (executable)
index 485b57f..0000000
+++ /dev/null
@@ -1,137 +0,0 @@
-
-// huffware script: no sitting on vendor, by fred huffhines.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// this message will be displayed when someone sits on the vendor.
-string AVATAR_MESSAGE = "You cannot sit here; I am a vendor, not a chair.  Please touch me for a notecard, or pay me to purchase the product.  Thanks!";
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();  // make sure newest addition is only version of script.
-        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);
-    }
-    
-    changed(integer change)
-    {
-        key id = llAvatarOnSitTarget();
-        if (change & CHANGED_LINK) {
-            if (id != NULL_KEY) {
-                llUnSit(id);
-                llDialog(id, AVATAR_MESSAGE, [], -981238);
-                    // we don't listen for the response.
-            }
-        }
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/noteworthy_example_usage_v3.6.lsl b/huffware/huffotronic_tools_n_testers_v6.1/noteworthy_example_usage_v3.6.lsl
new file mode 100755 (executable)
index 0000000..f955b64
--- /dev/null
@@ -0,0 +1,324 @@
+
+// huffware script: noteworthy example usage, by fred huffhines
+//
+// shows how to use the noteworthy script as a configuration helper.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+string EXAMPLE_NOTEWORTHY_SIGNATURE = "#example_noteworthy";
+    // the notecard must begin with this as its first line for it to be
+    // recognized as our configuration card.
+
+// global variables...
+
+string global_notecard_name;  // name of our notecard in the object's inventory.
+integer response_code;  // set to uniquely identify the notecard read in progress.
+list global_config_list;  // a collection of configuration parameters from our notecard.
+integer global_config_index;  // allows wrap-around feature, which we don't use here.
+
+// requires noteworthy library v8.3 or better.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+string BUSY_READING_INDICATOR = "busy_already";
+    // this return value indicates that the script is already in use by some other script.
+    // the calling script should try again later.
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be empty or missing.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or "bad_notecard" if none was found) and
+    // as subsequent elements an embedded list that was read from the notecard.  this
+    // necessarily limits the size of the notecards that we can read and return.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// this function fires off a request to the noteworthy library via a link message.
+// noteworthy will look for a notecard with our particular signature in it and
+// if it finds one, it will read the configuration therein.  an empty string is
+// returned if noteworthy couldn't find anything.
+request_configuration()
+{
+    global_notecard_name = "";  // reset any previous card.
+    // try to find a notecard with our configuration.
+    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([EXAMPLE_NOTEWORTHY_SIGNATURE, response_code]);
+    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+         parms_sent);
+}
+
+// processes link messages received from the noteworthy library.
+handle_link_message(integer which, integer num, string msg, key id)
+{
+    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
+            || (msg != READ_NOTECARD_COMMAND) )
+        return;  // not for us.
+    // process the result of reading the notecard.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string notecard_name = llList2String(parms, 0);
+    integer response_for = llList2Integer(parms, 1);
+    if (response_for != response_code) return;  // oops, this isn't for us.
+    if (notecard_name == BAD_NOTECARD_INDICATOR) {
+        // we hated the notecards we found, or there were none.
+        log_it("We apologize; there seem to be no notecards with a first line of '"
+            + EXAMPLE_NOTEWORTHY_SIGNATURE
+            + "'.  We can't read any configuration until that situation improves.");
+    } else {
+        // snag all but the first two elements for our config now.
+        global_config_list += llList2List(parms, 2, -1);
+        // make sure we shouldn't keep going.
+        if (notecard_name != NOTECARD_READ_CONTINUATION) {
+            // a valid notecard has been found.
+            global_notecard_name = notecard_name;  // record its name for later use.
+            global_config_index = 0;  // we are starting over in the config list.
+            // now echo the card we received...
+            log_it("read notecard \"" + global_notecard_name + "\":");
+            integer lines_to_say = llGetListLength(global_config_list);
+            if (lines_to_say > 8)
+                lines_to_say = 8;  // limit how much text is spoken.
+            integer indy;
+            for (indy = 0; indy < lines_to_say; indy++)
+                log_it("line #" + (string)(indy + 1) + ": " + llList2String(global_config_list, indy));
+            if (lines_to_say != llGetListLength(global_config_list))
+                log_it("...and so forth....");
+            // and process the file as a set of definitions.
+            process_ini_config();
+        }
+    }
+}
+
+///////////////
+
+// consumes the notecard in a very application specific way to retrieve our configuration items.
+// the example script only looks for two variables: name and description.  if those are found in
+// the sample card, then they are proudly shown.
+parse_variable_definition(string to_parse)
+{
+//    string content;  // filled after finding a variable name.
+//    if ( (content = get_variable_value(to_parse, "name")) != "")
+//        log_it("** got a name of '" + content + "'");
+//    else if ( (content = get_variable_value(to_parse, "description")) != "")
+//        log_it("** got a description of '" + content + "'");
+}
+
+initialize()
+{
+    // reset our relevant variables.
+    global_notecard_name = "";
+    global_config_list = [];
+    global_config_index = 0;
+
+    // announce that we're open for business.
+    log_it("example noteworthy usage is started, free mem=" + (string)llGetFreeMemory());
+
+    // request that the noteworthy library start looking for our notecard.
+    request_configuration();
+}
+
+//////////////
+// from hufflets...
+//
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// strips the spaces off of the beginning and end of a string.
+string strip_spaces(string to_strip)
+{
+    // clean out initial spaces.
+    while (llGetSubString(to_strip, 0, 0) == " ")
+        to_strip = llDeleteSubString(to_strip, 0, 0);
+    // clean out ending spaces.
+    while (llGetSubString(to_strip, -1, -1) == " ")
+        to_strip = llDeleteSubString(to_strip, -1, -1);
+    return to_strip;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+    return [ strip_spaces(x), strip_spaces(y) ];
+}
+
+// returns a non-empty string if "to_check" defines a value for "variable_name".
+// this must be in the form "X=Y", where X is the variable_name and Y is the value.
+string get_variable_value(string to_check, string variable_name)
+{
+    list x_y = separate_variable_definition(to_check);
+    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
+    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
+    return llList2String(x_y, 1);  // a match!
+}
+
+// examines all entries that we got from the notecard to see if any contain definitions.
+// this is basically an INI file reader, but it uses a list instead of a file.
+// ini files provide a format with multiple sections of config information, like so:
+//    [section_1]
+//    name1=value1
+//    name2=value2 ...etc...
+//    [section_2]
+//    name1=value1 ...etc...
+process_ini_config()
+{
+    log_it("scanning notecard for variable definitions...");
+    integer indy;
+    integer count = llGetListLength(global_config_list);
+    string section_name;  // set later if we see one.
+
+    // iterate across the items in our configuration to look for ones that are not done yet.            
+    for (indy = global_config_index; indy < count; indy++) {
+        string line = llList2String(global_config_list, indy);
+        // search for a section beginning.
+        if (llGetSubString(line, 0, 0) == "[") {
+            // we found the start of a section name.  now read the contents.
+            indy++;  // skip section line.
+            section_name = llGetSubString(line, 1, -2);
+            log_it("reading section: " + section_name);
+        }
+        integer sec_indy;
+        for (sec_indy = indy; sec_indy < count; sec_indy++) {
+            // read the lines in the section.
+            line = llList2String(global_config_list, sec_indy);
+            if (llGetSubString(line, 0, 0) != "[") {
+                // try to interpret this line as a variable setting.  this is just
+                // one example of a way to handle the config file; one might instead
+                // want to do something below once a whole section is read.
+                parse_variable_definition(line);
+                indy = sec_indy;  // track that we've passed this line.
+            } else {
+                // we're at the beginning of a new section now, so start processing its
+                // configuration in the outer loop.
+                indy = sec_indy - 1;  // set indy to proper beginning of section.
+                global_config_index = indy;  // remember where we had read to.
+                sec_indy = count + 3;  // skip remainder of inner loop.
+            }
+        }
+    }
+
+    global_config_index = 0;  // reset outer position if want to re-read.
+}
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (llGetInventoryName(inv_type, inv) == name_to_find)
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+// end hufflets
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        initialize();
+    }
+    
+    on_rez(integer parm) { llResetScript(); }
+    
+    touch_start(integer count) {
+        log_it("re-initializing script now to read card again...");
+        initialize();
+    }
+
+    // reset when we see changes to our notecard configuration.
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
+            llResetScript(); 
+        }
+    }
+    
+    // process the response from the noteworthy library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/noteworthy_example_usage_v3.6.txt b/huffware/huffotronic_tools_n_testers_v6.1/noteworthy_example_usage_v3.6.txt
deleted file mode 100755 (executable)
index f955b64..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-
-// huffware script: noteworthy example usage, by fred huffhines
-//
-// shows how to use the noteworthy script as a configuration helper.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-string EXAMPLE_NOTEWORTHY_SIGNATURE = "#example_noteworthy";
-    // the notecard must begin with this as its first line for it to be
-    // recognized as our configuration card.
-
-// global variables...
-
-string global_notecard_name;  // name of our notecard in the object's inventory.
-integer response_code;  // set to uniquely identify the notecard read in progress.
-list global_config_list;  // a collection of configuration parameters from our notecard.
-integer global_config_index;  // allows wrap-around feature, which we don't use here.
-
-// requires noteworthy library v8.3 or better.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-string BUSY_READING_INDICATOR = "busy_already";
-    // this return value indicates that the script is already in use by some other script.
-    // the calling script should try again later.
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be empty or missing.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or "bad_notecard" if none was found) and
-    // as subsequent elements an embedded list that was read from the notecard.  this
-    // necessarily limits the size of the notecards that we can read and return.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// this function fires off a request to the noteworthy library via a link message.
-// noteworthy will look for a notecard with our particular signature in it and
-// if it finds one, it will read the configuration therein.  an empty string is
-// returned if noteworthy couldn't find anything.
-request_configuration()
-{
-    global_notecard_name = "";  // reset any previous card.
-    // try to find a notecard with our configuration.
-    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([EXAMPLE_NOTEWORTHY_SIGNATURE, response_code]);
-    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-         parms_sent);
-}
-
-// processes link messages received from the noteworthy library.
-handle_link_message(integer which, integer num, string msg, key id)
-{
-    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
-            || (msg != READ_NOTECARD_COMMAND) )
-        return;  // not for us.
-    // process the result of reading the notecard.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string notecard_name = llList2String(parms, 0);
-    integer response_for = llList2Integer(parms, 1);
-    if (response_for != response_code) return;  // oops, this isn't for us.
-    if (notecard_name == BAD_NOTECARD_INDICATOR) {
-        // we hated the notecards we found, or there were none.
-        log_it("We apologize; there seem to be no notecards with a first line of '"
-            + EXAMPLE_NOTEWORTHY_SIGNATURE
-            + "'.  We can't read any configuration until that situation improves.");
-    } else {
-        // snag all but the first two elements for our config now.
-        global_config_list += llList2List(parms, 2, -1);
-        // make sure we shouldn't keep going.
-        if (notecard_name != NOTECARD_READ_CONTINUATION) {
-            // a valid notecard has been found.
-            global_notecard_name = notecard_name;  // record its name for later use.
-            global_config_index = 0;  // we are starting over in the config list.
-            // now echo the card we received...
-            log_it("read notecard \"" + global_notecard_name + "\":");
-            integer lines_to_say = llGetListLength(global_config_list);
-            if (lines_to_say > 8)
-                lines_to_say = 8;  // limit how much text is spoken.
-            integer indy;
-            for (indy = 0; indy < lines_to_say; indy++)
-                log_it("line #" + (string)(indy + 1) + ": " + llList2String(global_config_list, indy));
-            if (lines_to_say != llGetListLength(global_config_list))
-                log_it("...and so forth....");
-            // and process the file as a set of definitions.
-            process_ini_config();
-        }
-    }
-}
-
-///////////////
-
-// consumes the notecard in a very application specific way to retrieve our configuration items.
-// the example script only looks for two variables: name and description.  if those are found in
-// the sample card, then they are proudly shown.
-parse_variable_definition(string to_parse)
-{
-//    string content;  // filled after finding a variable name.
-//    if ( (content = get_variable_value(to_parse, "name")) != "")
-//        log_it("** got a name of '" + content + "'");
-//    else if ( (content = get_variable_value(to_parse, "description")) != "")
-//        log_it("** got a description of '" + content + "'");
-}
-
-initialize()
-{
-    // reset our relevant variables.
-    global_notecard_name = "";
-    global_config_list = [];
-    global_config_index = 0;
-
-    // announce that we're open for business.
-    log_it("example noteworthy usage is started, free mem=" + (string)llGetFreeMemory());
-
-    // request that the noteworthy library start looking for our notecard.
-    request_configuration();
-}
-
-//////////////
-// from hufflets...
-//
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// strips the spaces off of the beginning and end of a string.
-string strip_spaces(string to_strip)
-{
-    // clean out initial spaces.
-    while (llGetSubString(to_strip, 0, 0) == " ")
-        to_strip = llDeleteSubString(to_strip, 0, 0);
-    // clean out ending spaces.
-    while (llGetSubString(to_strip, -1, -1) == " ")
-        to_strip = llDeleteSubString(to_strip, -1, -1);
-    return to_strip;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-    return [ strip_spaces(x), strip_spaces(y) ];
-}
-
-// returns a non-empty string if "to_check" defines a value for "variable_name".
-// this must be in the form "X=Y", where X is the variable_name and Y is the value.
-string get_variable_value(string to_check, string variable_name)
-{
-    list x_y = separate_variable_definition(to_check);
-    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
-    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
-    return llList2String(x_y, 1);  // a match!
-}
-
-// examines all entries that we got from the notecard to see if any contain definitions.
-// this is basically an INI file reader, but it uses a list instead of a file.
-// ini files provide a format with multiple sections of config information, like so:
-//    [section_1]
-//    name1=value1
-//    name2=value2 ...etc...
-//    [section_2]
-//    name1=value1 ...etc...
-process_ini_config()
-{
-    log_it("scanning notecard for variable definitions...");
-    integer indy;
-    integer count = llGetListLength(global_config_list);
-    string section_name;  // set later if we see one.
-
-    // iterate across the items in our configuration to look for ones that are not done yet.            
-    for (indy = global_config_index; indy < count; indy++) {
-        string line = llList2String(global_config_list, indy);
-        // search for a section beginning.
-        if (llGetSubString(line, 0, 0) == "[") {
-            // we found the start of a section name.  now read the contents.
-            indy++;  // skip section line.
-            section_name = llGetSubString(line, 1, -2);
-            log_it("reading section: " + section_name);
-        }
-        integer sec_indy;
-        for (sec_indy = indy; sec_indy < count; sec_indy++) {
-            // read the lines in the section.
-            line = llList2String(global_config_list, sec_indy);
-            if (llGetSubString(line, 0, 0) != "[") {
-                // try to interpret this line as a variable setting.  this is just
-                // one example of a way to handle the config file; one might instead
-                // want to do something below once a whole section is read.
-                parse_variable_definition(line);
-                indy = sec_indy;  // track that we've passed this line.
-            } else {
-                // we're at the beginning of a new section now, so start processing its
-                // configuration in the outer loop.
-                indy = sec_indy - 1;  // set indy to proper beginning of section.
-                global_config_index = indy;  // remember where we had read to.
-                sec_indy = count + 3;  // skip remainder of inner loop.
-            }
-        }
-    }
-
-    global_config_index = 0;  // reset outer position if want to re-read.
-}
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (llGetInventoryName(inv_type, inv) == name_to_find)
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-// end hufflets
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        initialize();
-    }
-    
-    on_rez(integer parm) { llResetScript(); }
-    
-    touch_start(integer count) {
-        log_it("re-initializing script now to read card again...");
-        initialize();
-    }
-
-    // reset when we see changes to our notecard configuration.
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
-            llResetScript(); 
-        }
-    }
-    
-    // process the response from the noteworthy library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/report_to_merchants_v1.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/report_to_merchants_v1.3.lsl
new file mode 100755 (executable)
index 0000000..5e26542
--- /dev/null
@@ -0,0 +1,78 @@
+
+// huffware script: report to merchants, by fred huffhines.
+//
+// this script lets merchants know that one of their items has been rezzed or attached.
+// it only reports this the first time it happens.
+
+// global constants...
+
+integer SCRIPT_ZAPS_SELF_AFTER_REPORT = FALSE;
+    // if this is true, the script will destroy itself once it reports the object rez or attach.
+
+// the list of UUIDs for reporting the customer event.
+list IDS_TO_ALERT = [
+//    "addfa58f-e42e-4dde-9eb0-755bbf4e23ec",  // damara's alt.
+    "71649242-6abe-4288-b45b-a057621d35ea"   // fred.
+];
+
+// the list of emails that should be alerted.
+list EMAILS_TO_ALERT = [
+//    "damradbruch@hotmail.com",  // damara's alt email.
+    "fred@gruntose.com"         // fred.
+];
+
+// global variables...
+
+integer REPORTED_ABOUT_REZ = FALSE;  // did we tell the merchants yet?
+
+key CURRENT_OWNER = NULL_KEY;  // the guy who owns the hud right now.
+
+// helper functions...
+
+// let the merchants who sold this product know that it was either rezzed or attached.
+// either event should cause a nice report to them.
+alert_the_merchants(string word)
+{
+    integer i;
+    if (CURRENT_OWNER != llGetOwner()) {
+        // if the owner has changed, then we always believe that we need to report.
+        REPORTED_ABOUT_REZ = FALSE;
+        CURRENT_OWNER = llGetOwner();
+    }
+    if (!REPORTED_ABOUT_REZ) {
+        // we have not reported before (for this owner), so we can tell the merchants now.
+        REPORTED_ABOUT_REZ = TRUE;
+        string message_for_merchants = "Your product '" + llGetObjectName() + "' was "
+            + word + " by " + llKey2Name(llGetOwner())
+            + " in " + llGetRegionName()
+            + " at " + llGetTimestamp();
+        // send instant messages about this event.
+        for (i = 0; i < llGetListLength(IDS_TO_ALERT); i++) {
+            key id = (key)llList2String(IDS_TO_ALERT, i);
+            llInstantMessage(id, message_for_merchants);
+        }
+        // send emails about it too.
+        for (i = 0; i < llGetListLength(EMAILS_TO_ALERT); i++) {
+            string addr = llList2String(EMAILS_TO_ALERT, i);
+            llEmail(addr, "customer event for " + llKey2Name(llGetOwner())
+                + " regarding " + llGetObjectName(),
+                message_for_merchants);
+        }
+        // see if the script should go away now.
+        if (SCRIPT_ZAPS_SELF_AFTER_REPORT) {
+            llRemoveInventory(llGetScriptName());
+        }
+    }    
+}
+
+default
+{
+    state_entry() { CURRENT_OWNER = llGetOwner(); }
+    
+    attach(key id) {
+        if (id != NULL_KEY) { alert_the_merchants("attached"); }
+    }
+
+    on_rez(integer start_parm) { alert_the_merchants("rezzed"); }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/report_to_merchants_v1.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/report_to_merchants_v1.3.txt
deleted file mode 100755 (executable)
index 5e26542..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-
-// huffware script: report to merchants, by fred huffhines.
-//
-// this script lets merchants know that one of their items has been rezzed or attached.
-// it only reports this the first time it happens.
-
-// global constants...
-
-integer SCRIPT_ZAPS_SELF_AFTER_REPORT = FALSE;
-    // if this is true, the script will destroy itself once it reports the object rez or attach.
-
-// the list of UUIDs for reporting the customer event.
-list IDS_TO_ALERT = [
-//    "addfa58f-e42e-4dde-9eb0-755bbf4e23ec",  // damara's alt.
-    "71649242-6abe-4288-b45b-a057621d35ea"   // fred.
-];
-
-// the list of emails that should be alerted.
-list EMAILS_TO_ALERT = [
-//    "damradbruch@hotmail.com",  // damara's alt email.
-    "fred@gruntose.com"         // fred.
-];
-
-// global variables...
-
-integer REPORTED_ABOUT_REZ = FALSE;  // did we tell the merchants yet?
-
-key CURRENT_OWNER = NULL_KEY;  // the guy who owns the hud right now.
-
-// helper functions...
-
-// let the merchants who sold this product know that it was either rezzed or attached.
-// either event should cause a nice report to them.
-alert_the_merchants(string word)
-{
-    integer i;
-    if (CURRENT_OWNER != llGetOwner()) {
-        // if the owner has changed, then we always believe that we need to report.
-        REPORTED_ABOUT_REZ = FALSE;
-        CURRENT_OWNER = llGetOwner();
-    }
-    if (!REPORTED_ABOUT_REZ) {
-        // we have not reported before (for this owner), so we can tell the merchants now.
-        REPORTED_ABOUT_REZ = TRUE;
-        string message_for_merchants = "Your product '" + llGetObjectName() + "' was "
-            + word + " by " + llKey2Name(llGetOwner())
-            + " in " + llGetRegionName()
-            + " at " + llGetTimestamp();
-        // send instant messages about this event.
-        for (i = 0; i < llGetListLength(IDS_TO_ALERT); i++) {
-            key id = (key)llList2String(IDS_TO_ALERT, i);
-            llInstantMessage(id, message_for_merchants);
-        }
-        // send emails about it too.
-        for (i = 0; i < llGetListLength(EMAILS_TO_ALERT); i++) {
-            string addr = llList2String(EMAILS_TO_ALERT, i);
-            llEmail(addr, "customer event for " + llKey2Name(llGetOwner())
-                + " regarding " + llGetObjectName(),
-                message_for_merchants);
-        }
-        // see if the script should go away now.
-        if (SCRIPT_ZAPS_SELF_AFTER_REPORT) {
-            llRemoveInventory(llGetScriptName());
-        }
-    }    
-}
-
-default
-{
-    state_entry() { CURRENT_OWNER = llGetOwner(); }
-    
-    attach(key id) {
-        if (id != NULL_KEY) { alert_the_merchants("attached"); }
-    }
-
-    on_rez(integer start_parm) { alert_the_merchants("rezzed"); }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/set_roundy_v0.6.lsl b/huffware/huffotronic_tools_n_testers_v6.1/set_roundy_v0.6.lsl
new file mode 100755 (executable)
index 0000000..2ac6589
--- /dev/null
@@ -0,0 +1,130 @@
+
+// huffware script: set roundy, by fred huffhines.
+//
+// establishes properties for an object based on our ideal template.
+// really just a helper for the shop where we want to change a whole bunch of
+// product packages without recreating them.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry()
+    {
+        auto_retire();
+        
+        llSetPrimitiveParams([ PRIM_SIZE, <1.4, .164, 1.4>,  
+            PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0.0, 1.0, 0.0>, 0.0,
+                <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>,
+///                <0.0, 0.0, 0.0>, <0.0, 1.0, 0.0>,
+            PRIM_TEXTURE, ALL_SIDES, "c3c4ea17-90fd-d4e8-57e7-b39a47e1cea6",
+                <2, 1, 0>, <0.5, 0, 0>, 0
+//            PRIM_CHIPOPY
+        ]);
+    }
+
+    on_rez(integer parm) { llResetScript(); }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/set_roundy_v0.6.txt b/huffware/huffotronic_tools_n_testers_v6.1/set_roundy_v0.6.txt
deleted file mode 100755 (executable)
index 2ac6589..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-
-// huffware script: set roundy, by fred huffhines.
-//
-// establishes properties for an object based on our ideal template.
-// really just a helper for the shop where we want to change a whole bunch of
-// product packages without recreating them.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry()
-    {
-        auto_retire();
-        
-        llSetPrimitiveParams([ PRIM_SIZE, <1.4, .164, 1.4>,  
-            PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0.0, 1.0, 0.0>, 0.0,
-                <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>,
-///                <0.0, 0.0, 0.0>, <0.0, 1.0, 0.0>,
-            PRIM_TEXTURE, ALL_SIDES, "c3c4ea17-90fd-d4e8-57e7-b39a47e1cea6",
-                <2, 1, 0>, <0.5, 0, 0>, 0
-//            PRIM_CHIPOPY
-        ]);
-    }
-
-    on_rez(integer parm) { llResetScript(); }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/simple_map_tp_v0.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/simple_map_tp_v0.3.lsl
new file mode 100755 (executable)
index 0000000..5dd9965
--- /dev/null
@@ -0,0 +1,26 @@
+
+// huffware script: simple map tp, by fred huffhines.
+//
+// an inglorious little script for jumping somewhere else.
+
+string region = "hippocampus";
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+    }
+    
+    touch_start(integer count)
+    {
+        llWhisper(0, "Showing map of " + region + " for teleport...");
+        llMapDestination(region, <130, 130, 24>, ZERO_VECTOR);
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/simple_map_tp_v0.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/simple_map_tp_v0.3.txt
deleted file mode 100755 (executable)
index 5dd9965..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
-// huffware script: simple map tp, by fred huffhines.
-//
-// an inglorious little script for jumping somewhere else.
-
-string region = "hippocampus";
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-    }
-    
-    touch_start(integer count)
-    {
-        llWhisper(0, "Showing map of " + region + " for teleport...");
-        llMapDestination(region, <130, 130, 24>, ZERO_VECTOR);
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/simpy_pet_v3.7.lsl b/huffware/huffotronic_tools_n_testers_v6.1/simpy_pet_v3.7.lsl
new file mode 100755 (executable)
index 0000000..fa7549f
--- /dev/null
@@ -0,0 +1,174 @@
+
+// huffware script: simple follower script, by fred huffhines.
+//
+// this has been condensed from other pet scripts but still retains all the vitamins!
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+float HEIGHT_ABOVE_AVATAR = 0.3;  // how far above the av do we float.
+float ROOM_FOR_ERROR = 0.1;  // how far away from the target locale can we roam.
+float MAXIMUM_VELOCITY = 200.0;  // the fastest the object can zoom towards us.
+float SENSOR_PERIOD = 1.0;  // how frequently we look for the avatar.
+float SENSOR_RANGE =  64.0;  // the farthest away we will try to look for the avatar.
+
+// global variables...
+
+vector last_detected_position;  // where the avatar was last detected.
+integer target_identifier;  // the id assigned when we registered our target.
+integer last_physics_state;  // this remembers if physics should be enabled currently.
+vector perch_position;  // place we inhabit near the owner.    
+
+// returns the location where we should perch, given the target's location.
+vector target_to_perch(key av, vector target)
+{
+    vector av_bounds = llGetAgentSize(av);
+    return <target.x, target.y, target.z + av_bounds.z / 2.0 + HEIGHT_ABOVE_AVATAR>;
+}
+
+// returns the location of the target given where we're trying to aim at.
+vector perch_to_target(key av, vector perch)
+{
+    vector av_bounds = llGetAgentSize(av);
+    return <perch.x, perch.y, perch.z - av_bounds.z / 2 - HEIGHT_ABOVE_AVATAR>;
+}
+//hmmm: the two target and perch funcs both assume we don't want any lateral offset.
+//      and currently they're only taking into account the avatar's size in the z direction.
+
+
+// makes the pet completely stop travelling around and just sit there.
+cease_movement()
+{
+    llStopMoveToTarget();
+    llTargetRemove(target_identifier);
+    full_stop();        
+    llSetStatus(STATUS_PHYSICS, FALSE);
+    last_physics_state = FALSE;
+    // if we're not quite there, jump to the perch.
+    if (llVecDist(perch_position, llGetPos()) > ROOM_FOR_ERROR) {
+        // we're not close enough so make a flying leap.
+//llOwnerSay("jumping to perch at " + (string)perch_position + ", was at " + (string)llGetPos());
+        llSetPos(perch_position);  // make us very accurate until something changes.
+    }
+}
+
+// tells the pet to target the avatar "av" at the location "pos".  this will assume
+// the avatar is actually present in the same sim when it calculates the avatar's size.
+// we use that size in calculating where to perch nearby the avatar.
+move_toward_target(key av, vector destination)
+{
+    // first of all we'll remember where we're supposed to go.
+    perch_position = target_to_perch(av, destination);
+    // now see how far away we are from that.
+    float distance = llVecDist(perch_position, llGetPos());
+    if (distance < 1.0) {
+        // we're close enough; stop moving for a bit.
+//llOwnerSay("dist small enough to go non-phys: " + (string)distance);
+        cease_movement();
+        return;
+    }
+    // well, now we know that we need to move somewhere.  let's set up a
+    // physics target and head that way.
+    llSetStatus(STATUS_PHYSICS, TRUE);
+    last_physics_state = TRUE;
+    llTargetRemove(target_identifier);
+    float time = distance / MAXIMUM_VELOCITY;
+    // if we go too low, then SL will ignore the move to target request.
+    if (time < 0.14) time = 0.14;
+//llOwnerSay("tau=" + (string)time);
+    target_identifier = llTarget(perch_position, ROOM_FOR_ERROR);
+    llMoveToTarget(perch_position, time);
+}
+
+// startup the object.
+initialize()
+{
+    llSetStatus(STATUS_PHYSICS, TRUE);
+    last_physics_state = TRUE;
+    llSetBuoyancy(1.0);
+    llSetStatus(STATUS_PHANTOM, TRUE);
+    llSensorRemove();
+    // start looking for the owner.
+    llSensorRepeat("", llGetOwner(), AGENT, SENSOR_RANGE, PI * 2, SENSOR_PERIOD);
+}
+
+// sets the object's speed to "new_velocity".
+// if "local_axis" is TRUE, then it will be relative to the object's
+// own local coordinates.
+set_velocity(vector new_velocity, integer local_axis)
+{
+    vector current_velocity = llGetVel();
+         
+    if (local_axis) {
+        rotation rot = llGetRot();
+        current_velocity /= rot;  // undo the rotation.
+    }
+    
+    new_velocity -= current_velocity;
+    new_velocity *= llGetMass();
+    
+    llApplyImpulse(new_velocity, local_axis);
+}
+
+// attempts to bring the object to a complete stop.
+full_stop()
+{
+    llSetForce(<0,0,0>, FALSE);
+    set_velocity(<0,0,0>, FALSE);
+}
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { initialize(); }
+
+    on_rez(integer param) { llResetScript(); }
+
+    sensor(integer num_detected)
+    {
+        // save where we saw the av just now.
+        last_detected_position = llDetectedPos(0);
+        // move closer if we're not near enough to our beloved owner.
+        move_toward_target(llGetOwner(), last_detected_position);
+        // if we find that our rotation is incorrect, we'll fix that here.
+        // we only reorient on the sensor period, since that's slower
+        // than hitting our target.  plus we try to ensure we never get
+        // out of place again.
+        vector curr_rot = llRot2Euler(llGetRot());
+        if ( (curr_rot.x != 0.0 ) || (curr_rot.y != 0.0) ) {
+            // we are out of rotational goodness right now even.  fix that.
+            llSetStatus(STATUS_PHYSICS, FALSE);
+            llSetStatus(STATUS_ROTATE_X, FALSE);
+            llSetStatus(STATUS_ROTATE_Y, FALSE);
+            // save the z value before correcting the rotation.
+            vector new_rot = ZERO_VECTOR;
+            new_rot.z = curr_rot.z;
+            llSetRot(llEuler2Rot(new_rot));
+            llSetStatus(STATUS_PHYSICS, last_physics_state);
+        }
+    }
+
+    no_sensor()
+    {
+        // we lost track of the avatar.  turn off phyics and wait.
+        cease_movement();
+    }
+
+    at_target(integer number, vector targetpos, vector ourpos)
+    {
+        // wait until we see the av again before picking a new target.
+///??seems bad        cease_movement();
+    }
+    
+    not_at_target()
+    {
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/simpy_pet_v3.7.txt b/huffware/huffotronic_tools_n_testers_v6.1/simpy_pet_v3.7.txt
deleted file mode 100755 (executable)
index fa7549f..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-
-// huffware script: simple follower script, by fred huffhines.
-//
-// this has been condensed from other pet scripts but still retains all the vitamins!
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-float HEIGHT_ABOVE_AVATAR = 0.3;  // how far above the av do we float.
-float ROOM_FOR_ERROR = 0.1;  // how far away from the target locale can we roam.
-float MAXIMUM_VELOCITY = 200.0;  // the fastest the object can zoom towards us.
-float SENSOR_PERIOD = 1.0;  // how frequently we look for the avatar.
-float SENSOR_RANGE =  64.0;  // the farthest away we will try to look for the avatar.
-
-// global variables...
-
-vector last_detected_position;  // where the avatar was last detected.
-integer target_identifier;  // the id assigned when we registered our target.
-integer last_physics_state;  // this remembers if physics should be enabled currently.
-vector perch_position;  // place we inhabit near the owner.    
-
-// returns the location where we should perch, given the target's location.
-vector target_to_perch(key av, vector target)
-{
-    vector av_bounds = llGetAgentSize(av);
-    return <target.x, target.y, target.z + av_bounds.z / 2.0 + HEIGHT_ABOVE_AVATAR>;
-}
-
-// returns the location of the target given where we're trying to aim at.
-vector perch_to_target(key av, vector perch)
-{
-    vector av_bounds = llGetAgentSize(av);
-    return <perch.x, perch.y, perch.z - av_bounds.z / 2 - HEIGHT_ABOVE_AVATAR>;
-}
-//hmmm: the two target and perch funcs both assume we don't want any lateral offset.
-//      and currently they're only taking into account the avatar's size in the z direction.
-
-
-// makes the pet completely stop travelling around and just sit there.
-cease_movement()
-{
-    llStopMoveToTarget();
-    llTargetRemove(target_identifier);
-    full_stop();        
-    llSetStatus(STATUS_PHYSICS, FALSE);
-    last_physics_state = FALSE;
-    // if we're not quite there, jump to the perch.
-    if (llVecDist(perch_position, llGetPos()) > ROOM_FOR_ERROR) {
-        // we're not close enough so make a flying leap.
-//llOwnerSay("jumping to perch at " + (string)perch_position + ", was at " + (string)llGetPos());
-        llSetPos(perch_position);  // make us very accurate until something changes.
-    }
-}
-
-// tells the pet to target the avatar "av" at the location "pos".  this will assume
-// the avatar is actually present in the same sim when it calculates the avatar's size.
-// we use that size in calculating where to perch nearby the avatar.
-move_toward_target(key av, vector destination)
-{
-    // first of all we'll remember where we're supposed to go.
-    perch_position = target_to_perch(av, destination);
-    // now see how far away we are from that.
-    float distance = llVecDist(perch_position, llGetPos());
-    if (distance < 1.0) {
-        // we're close enough; stop moving for a bit.
-//llOwnerSay("dist small enough to go non-phys: " + (string)distance);
-        cease_movement();
-        return;
-    }
-    // well, now we know that we need to move somewhere.  let's set up a
-    // physics target and head that way.
-    llSetStatus(STATUS_PHYSICS, TRUE);
-    last_physics_state = TRUE;
-    llTargetRemove(target_identifier);
-    float time = distance / MAXIMUM_VELOCITY;
-    // if we go too low, then SL will ignore the move to target request.
-    if (time < 0.14) time = 0.14;
-//llOwnerSay("tau=" + (string)time);
-    target_identifier = llTarget(perch_position, ROOM_FOR_ERROR);
-    llMoveToTarget(perch_position, time);
-}
-
-// startup the object.
-initialize()
-{
-    llSetStatus(STATUS_PHYSICS, TRUE);
-    last_physics_state = TRUE;
-    llSetBuoyancy(1.0);
-    llSetStatus(STATUS_PHANTOM, TRUE);
-    llSensorRemove();
-    // start looking for the owner.
-    llSensorRepeat("", llGetOwner(), AGENT, SENSOR_RANGE, PI * 2, SENSOR_PERIOD);
-}
-
-// sets the object's speed to "new_velocity".
-// if "local_axis" is TRUE, then it will be relative to the object's
-// own local coordinates.
-set_velocity(vector new_velocity, integer local_axis)
-{
-    vector current_velocity = llGetVel();
-         
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    
-    new_velocity -= current_velocity;
-    new_velocity *= llGetMass();
-    
-    llApplyImpulse(new_velocity, local_axis);
-}
-
-// attempts to bring the object to a complete stop.
-full_stop()
-{
-    llSetForce(<0,0,0>, FALSE);
-    set_velocity(<0,0,0>, FALSE);
-}
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { initialize(); }
-
-    on_rez(integer param) { llResetScript(); }
-
-    sensor(integer num_detected)
-    {
-        // save where we saw the av just now.
-        last_detected_position = llDetectedPos(0);
-        // move closer if we're not near enough to our beloved owner.
-        move_toward_target(llGetOwner(), last_detected_position);
-        // if we find that our rotation is incorrect, we'll fix that here.
-        // we only reorient on the sensor period, since that's slower
-        // than hitting our target.  plus we try to ensure we never get
-        // out of place again.
-        vector curr_rot = llRot2Euler(llGetRot());
-        if ( (curr_rot.x != 0.0 ) || (curr_rot.y != 0.0) ) {
-            // we are out of rotational goodness right now even.  fix that.
-            llSetStatus(STATUS_PHYSICS, FALSE);
-            llSetStatus(STATUS_ROTATE_X, FALSE);
-            llSetStatus(STATUS_ROTATE_Y, FALSE);
-            // save the z value before correcting the rotation.
-            vector new_rot = ZERO_VECTOR;
-            new_rot.z = curr_rot.z;
-            llSetRot(llEuler2Rot(new_rot));
-            llSetStatus(STATUS_PHYSICS, last_physics_state);
-        }
-    }
-
-    no_sensor()
-    {
-        // we lost track of the avatar.  turn off phyics and wait.
-        cease_movement();
-    }
-
-    at_target(integer number, vector targetpos, vector ourpos)
-    {
-        // wait until we see the av again before picking a new target.
-///??seems bad        cease_movement();
-    }
-    
-    not_at_target()
-    {
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/sit_testing_v0.6.lsl b/huffware/huffotronic_tools_n_testers_v6.1/sit_testing_v0.6.lsl
new file mode 100755 (executable)
index 0000000..35445c8
--- /dev/null
@@ -0,0 +1,49 @@
+
+// testing of an opensim bug, where there was a new requirement that
+// the object have a sit target before any changed events will be fired.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer link_changes = 0;
+
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry()
+    {
+        llSitTarget(<0, 0, 0.1>, ZERO_ROTATION);
+//above line makes things work.  comment it out, and put in new object, and
+// the object will not get changed events.
+        llSay(0, "sit to run the test...");
+    }
+    
+    on_rez(integer count) { llResetScript(); }
+    
+    changed(integer chang) {
+        llSay(0, "got into changed event...");
+        if (! (chang & CHANGED_LINK) ) {
+            llSay(0, "change was not a link, leaving.");
+            return;  // not for us.
+        }
+        llSay(0, "into changed event, CHANGED_LINK...");
+        link_changes++;
+        key av_sitting = llAvatarOnSitTarget();
+        if (av_sitting == NULL_KEY) {
+            llSay(0, "avatar stood up since key is null");
+        } else {
+            llSay(0, "avatar sat down: " + llDetectedName(0));
+        }
+    }
+    
+    touch_start(integer count) {
+        llSay(0, "there have been " + (string)link_changes
+            + " 'changed' events for links since the last reset.");
+    }
+}
\ No newline at end of file
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/sit_testing_v0.6.txt b/huffware/huffotronic_tools_n_testers_v6.1/sit_testing_v0.6.txt
deleted file mode 100755 (executable)
index 35445c8..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-
-// testing of an opensim bug, where there was a new requirement that
-// the object have a sit target before any changed events will be fired.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer link_changes = 0;
-
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry()
-    {
-        llSitTarget(<0, 0, 0.1>, ZERO_ROTATION);
-//above line makes things work.  comment it out, and put in new object, and
-// the object will not get changed events.
-        llSay(0, "sit to run the test...");
-    }
-    
-    on_rez(integer count) { llResetScript(); }
-    
-    changed(integer chang) {
-        llSay(0, "got into changed event...");
-        if (! (chang & CHANGED_LINK) ) {
-            llSay(0, "change was not a link, leaving.");
-            return;  // not for us.
-        }
-        llSay(0, "into changed event, CHANGED_LINK...");
-        link_changes++;
-        key av_sitting = llAvatarOnSitTarget();
-        if (av_sitting == NULL_KEY) {
-            llSay(0, "avatar stood up since key is null");
-        } else {
-            llSay(0, "avatar sat down: " + llDetectedName(0));
-        }
-    }
-    
-    touch_start(integer count) {
-        llSay(0, "there have been " + (string)link_changes
-            + " 'changed' events for links since the last reset.");
-    }
-}
\ No newline at end of file
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/swiveller_v1.1.lsl b/huffware/huffotronic_tools_n_testers_v6.1/swiveller_v1.1.lsl
new file mode 100755 (executable)
index 0000000..d71062e
--- /dev/null
@@ -0,0 +1,193 @@
+
+//huffware script: swiveller, modified by fred huffhines.
+
+//original docs:
+// This script is as end-user friendly as possible. Moving the swing will make it reset to it's new position and orientation. Occasionally JUST rotating it won't work, so in that case you will need to nudge it sideways just a little (1mm will do). This is a quirk of LSL and it intermittent.
+// Put this script in the pivot - the thing the swing swings around (it doesn't have to be a long rod). That needs to be the root of the prim set that actually swings - if you want/need a frame that needs to be a separate item. SL doesn't yet allow us hierarchical linking.
+//
+// fred's modifications are licensed by:
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// configuration variables -- these control how the swing behaves.
+
+integer is_swinging = FALSE;  // if set to FALSE, then the swing is not running when rezzed.
+
+float SWING_PERIOD = 0.4;
+    // the delay between changing the swing's position.  decrease this number to increase
+    // speed of swinging.
+
+integer SWING_STEPS = 12;
+    // The total number of steps in the swing's path.  More steps makes for a
+    // smoother swing.  More steps (alone) means slower swinging also--time for
+    // a complete swing cycle is SWING_STEPS * swing_period.
+
+integer SWING_ANGLE_DEGREES = 10;
+    // How far from the vertical the swing will move.
+//This is in both directions?
+
+/////
+
+integer swing_step = 1;
+    // the current swing position.
+    
+float swingRad;
+
+vector normal;
+
+rotation Inverse(rotation r) { return <-r.x, -r.y, -r.z, r.s>; }
+
+rotation GetParentRot() { return Inverse(llGetLocalRot()) * llGetRot(); }
+
+SetLocalRot(rotation x) { llSetRot(x*Inverse(GetParentRot())); }
+
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        normal = llRot2Euler(llGetRot());
+        swingRad = SWING_ANGLE_DEGREES * DEG_TO_RAD;
+        llSetTouchText("Swing");
+    }
+    touch_start(integer num)
+    {
+        if (is_swinging) {
+            is_swinging = FALSE;
+            llSetTouchText("Swing");
+        } else {
+            is_swinging = TRUE;
+            llSetTouchText("Stop swing");
+            llSetTimerEvent(SWING_PERIOD);
+        }
+    }
+    timer()
+    {
+        float stepOffset = (float)swing_step / SWING_STEPS * TWO_PI;
+        if (swing_step > SWING_STEPS) swing_step = 1;
+        if (!is_swinging && (swing_step>=SWING_STEPS || swing_step==SWING_STEPS/2)) {
+            llSetTimerEvent(0.0);
+            SetLocalRot(llEuler2Rot(<normal.x, normal.y,
+                normal.z + swingRad*llSin(stepOffset)>));
+        } else {
+            SetLocalRot(llEuler2Rot(<normal.x, normal.y,
+                normal.z + swingRad*llSin(stepOffset)>));
+            swing_step++;
+        }
+    }
+    moving_end()
+    {
+        normal = llRot2Euler(llGetRot());
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/swiveller_v1.1.txt b/huffware/huffotronic_tools_n_testers_v6.1/swiveller_v1.1.txt
deleted file mode 100755 (executable)
index d71062e..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-
-//huffware script: swiveller, modified by fred huffhines.
-
-//original docs:
-// This script is as end-user friendly as possible. Moving the swing will make it reset to it's new position and orientation. Occasionally JUST rotating it won't work, so in that case you will need to nudge it sideways just a little (1mm will do). This is a quirk of LSL and it intermittent.
-// Put this script in the pivot - the thing the swing swings around (it doesn't have to be a long rod). That needs to be the root of the prim set that actually swings - if you want/need a frame that needs to be a separate item. SL doesn't yet allow us hierarchical linking.
-//
-// fred's modifications are licensed by:
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// configuration variables -- these control how the swing behaves.
-
-integer is_swinging = FALSE;  // if set to FALSE, then the swing is not running when rezzed.
-
-float SWING_PERIOD = 0.4;
-    // the delay between changing the swing's position.  decrease this number to increase
-    // speed of swinging.
-
-integer SWING_STEPS = 12;
-    // The total number of steps in the swing's path.  More steps makes for a
-    // smoother swing.  More steps (alone) means slower swinging also--time for
-    // a complete swing cycle is SWING_STEPS * swing_period.
-
-integer SWING_ANGLE_DEGREES = 10;
-    // How far from the vertical the swing will move.
-//This is in both directions?
-
-/////
-
-integer swing_step = 1;
-    // the current swing position.
-    
-float swingRad;
-
-vector normal;
-
-rotation Inverse(rotation r) { return <-r.x, -r.y, -r.z, r.s>; }
-
-rotation GetParentRot() { return Inverse(llGetLocalRot()) * llGetRot(); }
-
-SetLocalRot(rotation x) { llSetRot(x*Inverse(GetParentRot())); }
-
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        normal = llRot2Euler(llGetRot());
-        swingRad = SWING_ANGLE_DEGREES * DEG_TO_RAD;
-        llSetTouchText("Swing");
-    }
-    touch_start(integer num)
-    {
-        if (is_swinging) {
-            is_swinging = FALSE;
-            llSetTouchText("Swing");
-        } else {
-            is_swinging = TRUE;
-            llSetTouchText("Stop swing");
-            llSetTimerEvent(SWING_PERIOD);
-        }
-    }
-    timer()
-    {
-        float stepOffset = (float)swing_step / SWING_STEPS * TWO_PI;
-        if (swing_step > SWING_STEPS) swing_step = 1;
-        if (!is_swinging && (swing_step>=SWING_STEPS || swing_step==SWING_STEPS/2)) {
-            llSetTimerEvent(0.0);
-            SetLocalRot(llEuler2Rot(<normal.x, normal.y,
-                normal.z + swingRad*llSin(stepOffset)>));
-        } else {
-            SetLocalRot(llEuler2Rot(<normal.x, normal.y,
-                normal.z + swingRad*llSin(stepOffset)>));
-            swing_step++;
-        }
-    }
-    moving_end()
-    {
-        normal = llRot2Euler(llGetRot());
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/tester_for_inventory_exchanger_v1.0.lsl b/huffware/huffotronic_tools_n_testers_v6.1/tester_for_inventory_exchanger_v1.0.lsl
new file mode 100755 (executable)
index 0000000..688a3a9
--- /dev/null
@@ -0,0 +1,146 @@
+
+// huffware script: tester for inventory exchanger, by fred huffhines.
+//
+// makes sure that the inventory exchanger is working, although this currently
+// needs some manual inspection to be sure that the items are properly exchanged
+// with the child prims.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// requires inventory exchanger version 2.0 or better.
+//////////////
+// do not redefine these constants.
+integer INVENTORY_EXCHANGER_HUFFWARE_ID = 10021;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+//string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+// commands available via the library:
+string REGISTER_ASSETS_COMMAND = "#regis#";
+    // makes the root prim's inventory exchanger track a set of items which each participating
+    // child prim should have.  this command is only available to the root prim; child prims
+    // cannot register any assets but instead can get updates on the assets.  the parameter
+    // required is a list of asset definitions, wrapped by the huffware item separator.  each
+    // asset definition is in turn a two part list wrapped with the asset field separator.
+string ASSET_FIELD_SEPARATOR = "&&";  // separates the type from the name in our list.
+string WILDCARD_INVENTORY_NAME = "ALL";
+    // this keyword can be used to register all of the inventory items available of the
+    // specified type.  this should be passed as the inventory item name in the second half of
+    // an asset definition list.
+string WHACK_INVENTORY_SIGNAL = "DEL*";
+    // ensures that the child prim doesn't maintain *any* of the inventory of the type specified.
+string AVAILABLE_ASSETS_EVENT = "#gotz#";
+    // the root prim publishes this event to list out what items it has available.  the child
+    // prims need to ask for anything that they're currently missing.  the included parameters
+    // are in the same format as the register assets command, but no wildcards will be present;
+    // all asset names will be fully expanded.
+string REQUEST_UPDATES = "#nupd#";
+    // used by the child prim to request an updated version of an asset or assets.  the parameters
+    // should follow the register assets command.
+string FINISHED_UPDATING = "#donq#";
+    // a signal sent from the root prim to the child prim when the root has finished updating
+    // the assets requested.  this lets the child know that it can clean out any outdated versions
+    // of items which got an update.  there are no parameters to this, because the child prim
+    // should have at most one update outstanding at a time.
+//////////////
+
+// looks for an inventory item with the same prefix as the "basename_to_seek".
+integer find_basename_in_inventory(string basename_to_seek, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer indy;
+    for (indy = 0; indy < num_inv; indy++) {
+        if (is_prefix(llGetInventoryName(inv_type, indy), basename_to_seek))
+            return indy;
+    }
+    return -2;  // failed to find it.
+}
+
+// returns the name of the inventory exchange script, if one is present.  we don't worry
+// about there being more than one present; that's a different script's problem rather
+// than one from the inventory exchanger.
+string get_exchangers_name()
+{
+    integer found = find_basename_in_inventory("inventory exchanger", INVENTORY_SCRIPT);
+    if (found < 0) {
+        return "";
+    }
+    return llGetInventoryName(INVENTORY_SCRIPT, found);
+}
+
+// tell the root prim's inventory exchanger what to monitor.
+post_exchangeable_assets()
+{
+    llMessageLinked(LINK_THIS, INVENTORY_EXCHANGER_HUFFWARE_ID, REGISTER_ASSETS_COMMAND,
+        wrap_parameters([
+            (string)INVENTORY_LANDMARK + ASSET_FIELD_SEPARATOR + "ALL",
+            (string)INVENTORY_SOUND + ASSET_FIELD_SEPARATOR + "ALL",
+            (string)INVENTORY_SCRIPT + ASSET_FIELD_SEPARATOR + get_exchangers_name(),
+            (string)INVENTORY_TEXTURE + ASSET_FIELD_SEPARATOR +  "ALL"
+        ]));
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// end hufflets.
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry()
+    {
+        llSetTimerEvent(14);  // pretty fast update cycle will push the exchange events.
+        post_exchangeable_assets();
+    }
+
+    // this tester has no link message responsibilities.  once it tells the root prim's
+    // inventory exchanger what to do, that's all it needs to say.
+//    link_message(integer link_num, integer service, string cmd, key parms) {}
+    
+    timer() {
+        // repost all the assets we care about.  this ensures that we're up to date if the
+        // inventory changes.
+        post_exchangeable_assets();
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/tester_for_inventory_exchanger_v1.0.txt b/huffware/huffotronic_tools_n_testers_v6.1/tester_for_inventory_exchanger_v1.0.txt
deleted file mode 100755 (executable)
index 688a3a9..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-
-// huffware script: tester for inventory exchanger, by fred huffhines.
-//
-// makes sure that the inventory exchanger is working, although this currently
-// needs some manual inspection to be sure that the items are properly exchanged
-// with the child prims.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// requires inventory exchanger version 2.0 or better.
-//////////////
-// do not redefine these constants.
-integer INVENTORY_EXCHANGER_HUFFWARE_ID = 10021;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-//string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-// commands available via the library:
-string REGISTER_ASSETS_COMMAND = "#regis#";
-    // makes the root prim's inventory exchanger track a set of items which each participating
-    // child prim should have.  this command is only available to the root prim; child prims
-    // cannot register any assets but instead can get updates on the assets.  the parameter
-    // required is a list of asset definitions, wrapped by the huffware item separator.  each
-    // asset definition is in turn a two part list wrapped with the asset field separator.
-string ASSET_FIELD_SEPARATOR = "&&";  // separates the type from the name in our list.
-string WILDCARD_INVENTORY_NAME = "ALL";
-    // this keyword can be used to register all of the inventory items available of the
-    // specified type.  this should be passed as the inventory item name in the second half of
-    // an asset definition list.
-string WHACK_INVENTORY_SIGNAL = "DEL*";
-    // ensures that the child prim doesn't maintain *any* of the inventory of the type specified.
-string AVAILABLE_ASSETS_EVENT = "#gotz#";
-    // the root prim publishes this event to list out what items it has available.  the child
-    // prims need to ask for anything that they're currently missing.  the included parameters
-    // are in the same format as the register assets command, but no wildcards will be present;
-    // all asset names will be fully expanded.
-string REQUEST_UPDATES = "#nupd#";
-    // used by the child prim to request an updated version of an asset or assets.  the parameters
-    // should follow the register assets command.
-string FINISHED_UPDATING = "#donq#";
-    // a signal sent from the root prim to the child prim when the root has finished updating
-    // the assets requested.  this lets the child know that it can clean out any outdated versions
-    // of items which got an update.  there are no parameters to this, because the child prim
-    // should have at most one update outstanding at a time.
-//////////////
-
-// looks for an inventory item with the same prefix as the "basename_to_seek".
-integer find_basename_in_inventory(string basename_to_seek, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer indy;
-    for (indy = 0; indy < num_inv; indy++) {
-        if (is_prefix(llGetInventoryName(inv_type, indy), basename_to_seek))
-            return indy;
-    }
-    return -2;  // failed to find it.
-}
-
-// returns the name of the inventory exchange script, if one is present.  we don't worry
-// about there being more than one present; that's a different script's problem rather
-// than one from the inventory exchanger.
-string get_exchangers_name()
-{
-    integer found = find_basename_in_inventory("inventory exchanger", INVENTORY_SCRIPT);
-    if (found < 0) {
-        return "";
-    }
-    return llGetInventoryName(INVENTORY_SCRIPT, found);
-}
-
-// tell the root prim's inventory exchanger what to monitor.
-post_exchangeable_assets()
-{
-    llMessageLinked(LINK_THIS, INVENTORY_EXCHANGER_HUFFWARE_ID, REGISTER_ASSETS_COMMAND,
-        wrap_parameters([
-            (string)INVENTORY_LANDMARK + ASSET_FIELD_SEPARATOR + "ALL",
-            (string)INVENTORY_SOUND + ASSET_FIELD_SEPARATOR + "ALL",
-            (string)INVENTORY_SCRIPT + ASSET_FIELD_SEPARATOR + get_exchangers_name(),
-            (string)INVENTORY_TEXTURE + ASSET_FIELD_SEPARATOR +  "ALL"
-        ]));
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// end hufflets.
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry()
-    {
-        llSetTimerEvent(14);  // pretty fast update cycle will push the exchange events.
-        post_exchangeable_assets();
-    }
-
-    // this tester has no link message responsibilities.  once it tells the root prim's
-    // inventory exchanger what to do, that's all it needs to say.
-//    link_message(integer link_num, integer service, string cmd, key parms) {}
-    
-    timer() {
-        // repost all the assets we care about.  this ensures that we're up to date if the
-        // inventory changes.
-        post_exchangeable_assets();
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/time_zone_picker_v0.6.lsl b/huffware/huffotronic_tools_n_testers_v6.1/time_zone_picker_v0.6.lsl
new file mode 100755 (executable)
index 0000000..b435645
--- /dev/null
@@ -0,0 +1,222 @@
+
+// huffware script: time zone picker, by fred huffhines.
+//
+// allows the user to select a different time zone than the default.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants...
+
+// secret codes to control the time zone.
+integer SECRET_TIME_ZONE_ADJUSTER_ID = -2091823;
+string TIME_ZONE_ADJUST_COMMAND = "tzadjust";
+
+// requires menutini v3.9 or better...
+//////////////
+// do not redefine these constants.
+integer MENUTINI_HUFFWARE_ID = 10009;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+// commands available via menutini:
+string SHOW_MENU_COMMAND = "#menu#";
+    // the command that tells menutini to show a menu defined by parameters
+    // that are passed along.  these must be: the menu name, the menu's title
+    // (which is really the info to show as content in the main box of the menu),
+    // the wrapped list of commands to show as menu buttons, the menu system
+    // channel's for listening, and the key to listen to.
+//
+//////////////
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+//
+//////////////
+
+integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
+
+simply_display_menu(string menu_name, string title, list buttons)
+{
+    integer menu_channel = random_channel();
+    key listen_to = llGetOwner();
+    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
+        menu_name + HUFFWARE_PARM_SEPARATOR
+        + title + HUFFWARE_PARM_SEPARATOR
+        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
+        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
+        + (string)listen_to);
+}
+
+// handles the response message when the user chooses a button.
+react_to_menu(string menu_name, string av_key, string which_choice)
+{
+    log_it("You selected a time zone offset of " + which_choice);
+    llMessageLinked(LINK_SET, SECRET_TIME_ZONE_ADJUSTER_ID, TIME_ZONE_ADJUST_COMMAND, which_choice);
+}
+
+// processes a message from a link.  some of this must be handled
+// by the driver script that handles our configuration.
+handle_link_message(integer sender, integer num, string msg, key id)
+{
+    if ( (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE)
+        || (msg != SHOW_MENU_COMMAND) ) return;  // not for us.
+
+//log_it("menu reply: sndr=" + (string)sender + " num=" + (string)num + " msg=" + msg + " id=" + (string)id);
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string menu_name = llList2String(parms, 0);
+    string which_choice = llList2String(parms, 1);
+    key av_key = llList2String(parms, 2);
+    react_to_menu(menu_name, av_key, which_choice);
+}
+
+//////////////
+// from hufflets...
+//
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+//
+// end hufflets
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();  // make sure newest addition is only version of script.
+    }
+
+    touch_start(integer touchers) {
+        if (llDetectedKey(0) != llGetOwner()) return;  // only listen to owner for setting time zone.
+        simply_display_menu("tz", "Select your time zone offset from GMT:\nGMT is 0, EST is -5, PST is -8, etc.",
+            [ -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ] );
+    }
+
+    link_message(integer sender, integer num, string msg, key id)
+    { handle_link_message(sender, num, msg, id); }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/time_zone_picker_v0.6.txt b/huffware/huffotronic_tools_n_testers_v6.1/time_zone_picker_v0.6.txt
deleted file mode 100755 (executable)
index b435645..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-
-// huffware script: time zone picker, by fred huffhines.
-//
-// allows the user to select a different time zone than the default.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants...
-
-// secret codes to control the time zone.
-integer SECRET_TIME_ZONE_ADJUSTER_ID = -2091823;
-string TIME_ZONE_ADJUST_COMMAND = "tzadjust";
-
-// requires menutini v3.9 or better...
-//////////////
-// do not redefine these constants.
-integer MENUTINI_HUFFWARE_ID = 10009;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-// commands available via menutini:
-string SHOW_MENU_COMMAND = "#menu#";
-    // the command that tells menutini to show a menu defined by parameters
-    // that are passed along.  these must be: the menu name, the menu's title
-    // (which is really the info to show as content in the main box of the menu),
-    // the wrapped list of commands to show as menu buttons, the menu system
-    // channel's for listening, and the key to listen to.
-//
-//////////////
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-//
-//////////////
-
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-
-simply_display_menu(string menu_name, string title, list buttons)
-{
-    integer menu_channel = random_channel();
-    key listen_to = llGetOwner();
-    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
-        menu_name + HUFFWARE_PARM_SEPARATOR
-        + title + HUFFWARE_PARM_SEPARATOR
-        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
-        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
-        + (string)listen_to);
-}
-
-// handles the response message when the user chooses a button.
-react_to_menu(string menu_name, string av_key, string which_choice)
-{
-    log_it("You selected a time zone offset of " + which_choice);
-    llMessageLinked(LINK_SET, SECRET_TIME_ZONE_ADJUSTER_ID, TIME_ZONE_ADJUST_COMMAND, which_choice);
-}
-
-// processes a message from a link.  some of this must be handled
-// by the driver script that handles our configuration.
-handle_link_message(integer sender, integer num, string msg, key id)
-{
-    if ( (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE)
-        || (msg != SHOW_MENU_COMMAND) ) return;  // not for us.
-
-//log_it("menu reply: sndr=" + (string)sender + " num=" + (string)num + " msg=" + msg + " id=" + (string)id);
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string menu_name = llList2String(parms, 0);
-    string which_choice = llList2String(parms, 1);
-    key av_key = llList2String(parms, 2);
-    react_to_menu(menu_name, av_key, which_choice);
-}
-
-//////////////
-// from hufflets...
-//
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-//
-// end hufflets
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();  // make sure newest addition is only version of script.
-    }
-
-    touch_start(integer touchers) {
-        if (llDetectedKey(0) != llGetOwner()) return;  // only listen to owner for setting time zone.
-        simply_display_menu("tz", "Select your time zone offset from GMT:\nGMT is 0, EST is -5, PST is -8, etc.",
-            [ -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ] );
-    }
-
-    link_message(integer sender, integer num, string msg, key id)
-    { handle_link_message(sender, num, msg, id); }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/timed_expiration_v2.9_(toxic)_.lsl b/huffware/huffotronic_tools_n_testers_v6.1/timed_expiration_v2.9_(toxic)_.lsl
new file mode 100755 (executable)
index 0000000..c3fe964
--- /dev/null
@@ -0,0 +1,159 @@
+
+// huffware script: timed expiration, by fred huffhines.
+//
+// this ensures that an object only lives a set amount of time before de-rezzing.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+float PRODUCT_LIFETIME = 0.9;  // time allowed before the object terminates, in minutes.
+    // since we now make the object temporary, this has to be less than a minute
+    // for our own dying scene to take place.  otherwise the object just disappears.
+
+float EXPIRY_VOLUME = 0.25;
+    // we have found that this volume level is generally good, since you don't want
+    // the object screaming like crazy as it evaporates.
+
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 1.9.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+//
+// example usage of the auto-retirement script:
+//
+// default {
+//    state_entry() {
+//        auto_retire();  // make sure newest addition is only version of script.
+//    }
+// }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                if ((float)inv_version_string < (float)version_string) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
+        
+    string basename = to_chop_up;  // script name with no version attached.
+    
+    integer posn;
+    // minimum script name is 2 characters plus version.
+    for (posn = llStringLength(to_chop_up) - 1;
+        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
+        posn--) {
+        // find the space.  do nothing else.
+    }
+    if (posn < 2) return [];  // no space found.
+    string full_suffix = llGetSubString(to_chop_up, posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// how many times the timer is hit per minute.
+float TICKS_PER_MINUTE = 20.0;
+
+float ticks_to_live;  // how long this particular object has left.
+
+show_time_left()
+{
+//    integer secs_left = (integer)(60.0 * ticks_to_live / TICKS_PER_MINUTE);
+//    llWhisper(14, (string)secs_left + " seconds before expiration.");
+}
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        llParticleSystem([]);  // kill any old particles running.
+        auto_retire();
+//llWhisper(0, "starting up " + llGetObjectName());
+        ticks_to_live = PRODUCT_LIFETIME * TICKS_PER_MINUTE;
+        llSetTimerEvent(60.0 / TICKS_PER_MINUTE);  // check avatar's state periodically.
+        // make sure this is a temporary object.
+        llSetPrimitiveParams([PRIM_TEMP_ON_REZ, TRUE]);
+        show_time_left();
+    }
+
+    timer() {
+        // make sure we don't wait too long to reset our temporariness.
+        integer time_now = llGetUnixTime();
+        // check whether we should stay alive or not.
+        if (--ticks_to_live <= 0.0) {
+//            llWhisper(0, llGetObjectName() + " is terminating now.");
+            string first_sound = llGetInventoryName(INVENTORY_SOUND, 0);
+            if (first_sound != "")
+                llTriggerSound(first_sound, EXPIRY_VOLUME);
+            string first_pic = llGetInventoryName(INVENTORY_TEXTURE, 0);
+            if (first_pic != "")
+                llMakeExplosion(20, 1.0, 5, 3.0, 1.0, first_pic, ZERO_VECTOR);
+            llDie();
+            // resetting this since if we're here, we don't want to keep blowing up.
+            ticks_to_live = PRODUCT_LIFETIME * TICKS_PER_MINUTE;
+        } else {
+            show_time_left();
+        }
+    }
+    
+    on_rez(integer param) {
+        // make sure we start over when this is a new object.
+        llResetScript();
+    }
+    
+    touch_start(integer total_number)
+    {
+        ticks_to_live += TICKS_PER_MINUTE;  // add a minute to its life.
+//        llWhisper(0, "Object gets another minute to live.");
+    }
+
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/timed_expiration_v2.9_(toxic)_.txt b/huffware/huffotronic_tools_n_testers_v6.1/timed_expiration_v2.9_(toxic)_.txt
deleted file mode 100755 (executable)
index c3fe964..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-
-// huffware script: timed expiration, by fred huffhines.
-//
-// this ensures that an object only lives a set amount of time before de-rezzing.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-float PRODUCT_LIFETIME = 0.9;  // time allowed before the object terminates, in minutes.
-    // since we now make the object temporary, this has to be less than a minute
-    // for our own dying scene to take place.  otherwise the object just disappears.
-
-float EXPIRY_VOLUME = 0.25;
-    // we have found that this volume level is generally good, since you don't want
-    // the object screaming like crazy as it evaporates.
-
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 1.9.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-//
-// example usage of the auto-retirement script:
-//
-// default {
-//    state_entry() {
-//        auto_retire();  // make sure newest addition is only version of script.
-//    }
-// }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                if ((float)inv_version_string < (float)version_string) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
-        
-    string basename = to_chop_up;  // script name with no version attached.
-    
-    integer posn;
-    // minimum script name is 2 characters plus version.
-    for (posn = llStringLength(to_chop_up) - 1;
-        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
-        posn--) {
-        // find the space.  do nothing else.
-    }
-    if (posn < 2) return [];  // no space found.
-    string full_suffix = llGetSubString(to_chop_up, posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// how many times the timer is hit per minute.
-float TICKS_PER_MINUTE = 20.0;
-
-float ticks_to_live;  // how long this particular object has left.
-
-show_time_left()
-{
-//    integer secs_left = (integer)(60.0 * ticks_to_live / TICKS_PER_MINUTE);
-//    llWhisper(14, (string)secs_left + " seconds before expiration.");
-}
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        llParticleSystem([]);  // kill any old particles running.
-        auto_retire();
-//llWhisper(0, "starting up " + llGetObjectName());
-        ticks_to_live = PRODUCT_LIFETIME * TICKS_PER_MINUTE;
-        llSetTimerEvent(60.0 / TICKS_PER_MINUTE);  // check avatar's state periodically.
-        // make sure this is a temporary object.
-        llSetPrimitiveParams([PRIM_TEMP_ON_REZ, TRUE]);
-        show_time_left();
-    }
-
-    timer() {
-        // make sure we don't wait too long to reset our temporariness.
-        integer time_now = llGetUnixTime();
-        // check whether we should stay alive or not.
-        if (--ticks_to_live <= 0.0) {
-//            llWhisper(0, llGetObjectName() + " is terminating now.");
-            string first_sound = llGetInventoryName(INVENTORY_SOUND, 0);
-            if (first_sound != "")
-                llTriggerSound(first_sound, EXPIRY_VOLUME);
-            string first_pic = llGetInventoryName(INVENTORY_TEXTURE, 0);
-            if (first_pic != "")
-                llMakeExplosion(20, 1.0, 5, 3.0, 1.0, first_pic, ZERO_VECTOR);
-            llDie();
-            // resetting this since if we're here, we don't want to keep blowing up.
-            ticks_to_live = PRODUCT_LIFETIME * TICKS_PER_MINUTE;
-        } else {
-            show_time_left();
-        }
-    }
-    
-    on_rez(integer param) {
-        // make sure we start over when this is a new object.
-        llResetScript();
-    }
-    
-    touch_start(integer total_number)
-    {
-        ticks_to_live += TICKS_PER_MINUTE;  // add a minute to its life.
-//        llWhisper(0, "Object gets another minute to live.");
-    }
-
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/touchy_feely_doro_v0.4.lsl b/huffware/huffotronic_tools_n_testers_v6.1/touchy_feely_doro_v0.4.lsl
new file mode 100755 (executable)
index 0000000..7aeaed8
--- /dev/null
@@ -0,0 +1,19 @@
+
+// 
+// used to control the door into the inner chamber of the old garleon
+// land, where we had a basement with a crypt door.  this was in the rocks
+// near the door.  it actually will work with any tl linked door script set
+// to our 108 channel, but it currently shouts, which will fling all the nearby
+// doors open.
+
+default
+{
+    state_entry()
+    {
+    }
+
+    touch_start(integer total_number)
+    {
+        if (llSameGroup(llDetectedKey(0))) llShout(108, "toggle");
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/touchy_feely_doro_v0.4.txt b/huffware/huffotronic_tools_n_testers_v6.1/touchy_feely_doro_v0.4.txt
deleted file mode 100755 (executable)
index 7aeaed8..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-// 
-// used to control the door into the inner chamber of the old garleon
-// land, where we had a basement with a crypt door.  this was in the rocks
-// near the door.  it actually will work with any tl linked door script set
-// to our 108 channel, but it currently shouts, which will fling all the nearby
-// doors open.
-
-default
-{
-    state_entry()
-    {
-    }
-
-    touch_start(integer total_number)
-    {
-        if (llSameGroup(llDetectedKey(0))) llShout(108, "toggle");
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/turbo_lifter_v5.7.lsl b/huffware/huffotronic_tools_n_testers_v6.1/turbo_lifter_v5.7.lsl
new file mode 100755 (executable)
index 0000000..a233a40
--- /dev/null
@@ -0,0 +1,247 @@
+
+// huffware script: turbo lifter, by fred huffhines
+
+// constants you may want to adjust...
+
+float minimum_height = 0.5;
+    // the lowest that the lifter will move -- relative to ground height.
+
+float maximum_height = 1007.5;
+    // the highest that the platform will move in absolute height (not relative to ground!).
+
+// the rationale for having the minimum be based on ground height and the maximum be based
+// on absolute heights is that it is often the case that one wants to have the elevator meet
+// people at the ground, and then take them high up in the clouds.  given that main usage
+// pattern, we've found it way more convenient to reckon the base against ground but leave
+// the top absolute so we can match sky houses et al.
+    
+float movement_per_cycle = 100.0;
+    // how much change in height occurs per timer hit.
+
+integer SLEEP_DURATION = 28;
+    // how long the elevator pauses at the stations.
+  
+integer PAUSE_DURATION = 14;
+    // the delay added when a user clicks on the elevator.
+
+integer COUNTDOWN_INTERVAL = 8;
+   // the frequency of the countdown message about departure.
+
+integer WHISPER_COUNTDOWN = FALSE;
+    // if TRUE, the elevator will count down its departure schedule.
+
+//////////////
+
+// requires: jaunting library v14.0 or higher.
+//////////////
+integer JAUNT_HUFFWARE_ID = 10008;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+string JAUNT_COMMAND = "#jaunt#";
+    // command used to tell jaunt script to move object.
+//////////////
+
+//////////////
+
+// global variables and their default values...
+
+integer going_up = FALSE;
+    // remembers which direction the platform is moving.
+
+integer next_movement;
+    // when the lift should next move.  delayed for stations and
+    // when user chooses to delay take-off.
+
+//////////////
+
+float height_above_ground()
+{
+    vector position = llGetPos();
+    vector size = llGetAgentSize(llGetOwner()); 
+    return position.z - llGround(<0.0,0.0,0.0>) - size.z;
+}
+
+jaunt_to_target(vector target)
+{
+    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_COMMAND, (string)target);
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        // initialize the next movement so elevator doesn't just zoom off.
+        next_movement = llGetUnixTime() + (integer)SLEEP_DURATION;
+        // we move at one second intervals due to our use of unix time,
+        // which has a resolution of seconds.
+        llSetTimerEvent(1.0);
+    }
+    
+//need commands, like start, or call to come down.
+// need elevator system that would call it.
+//  if elevator style deal, needs to not delay so silly like.
+//    when jaunting, go go go.
+    
+    timer()
+    {
+        integer time_now = llGetUnixTime();
+        // make sure it's time to do something.
+        if (time_now < next_movement) {
+            integer time_left = next_movement - time_now;
+            if ( (time_left <= 2) || !(time_left % COUNTDOWN_INTERVAL) ) {
+                if (WHISPER_COUNTDOWN) {
+//hmmm: abstract pluralizer out as separate function.
+                    string plural = "s";
+                    if (time_left == 1) plural = "";
+                    llWhisper(0, "Time remaining before departure: "
+                        + (string)time_left + " second" + plural + ".");
+                }
+            }
+            return;  // not time to move yet.
+        }
+        // set the next movement time to be without any delay, until we know better.
+        next_movement = llGetUnixTime();
+        // compute where we should jump to next.        
+        vector next_location = llGetPos();
+        // add in the appropriate amount to our height.
+        if (going_up) next_location += <0.0, 0.0, movement_per_cycle>;
+        else next_location -= <0.0, 0.0, movement_per_cycle>;
+        // check whether we've hit one of our extremes.
+        if (next_location.z >= maximum_height) {
+            going_up = FALSE;  // start going down.
+            next_movement = llGetUnixTime() + (integer)SLEEP_DURATION;
+            next_location.z = maximum_height;
+        } else if (next_location.z <= minimum_height + llGround(<0.0,0.0,0.0>)) {
+            going_up = TRUE;  // begin going up.
+            next_movement = llGetUnixTime() + (integer)SLEEP_DURATION;
+            next_location.z = minimum_height + llGround(<0.0,0.0,0.0>);
+        }
+        // now actually go to where we decided.
+        jaunt_to_target(next_location);
+    }
+
+    touch_start(integer total_number)
+    {
+        next_movement += (integer)PAUSE_DURATION;
+        llWhisper(0, "Your click delays departure by " + (string)PAUSE_DURATION + " seconds.");
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/turbo_lifter_v5.7.txt b/huffware/huffotronic_tools_n_testers_v6.1/turbo_lifter_v5.7.txt
deleted file mode 100755 (executable)
index a233a40..0000000
+++ /dev/null
@@ -1,247 +0,0 @@
-
-// huffware script: turbo lifter, by fred huffhines
-
-// constants you may want to adjust...
-
-float minimum_height = 0.5;
-    // the lowest that the lifter will move -- relative to ground height.
-
-float maximum_height = 1007.5;
-    // the highest that the platform will move in absolute height (not relative to ground!).
-
-// the rationale for having the minimum be based on ground height and the maximum be based
-// on absolute heights is that it is often the case that one wants to have the elevator meet
-// people at the ground, and then take them high up in the clouds.  given that main usage
-// pattern, we've found it way more convenient to reckon the base against ground but leave
-// the top absolute so we can match sky houses et al.
-    
-float movement_per_cycle = 100.0;
-    // how much change in height occurs per timer hit.
-
-integer SLEEP_DURATION = 28;
-    // how long the elevator pauses at the stations.
-  
-integer PAUSE_DURATION = 14;
-    // the delay added when a user clicks on the elevator.
-
-integer COUNTDOWN_INTERVAL = 8;
-   // the frequency of the countdown message about departure.
-
-integer WHISPER_COUNTDOWN = FALSE;
-    // if TRUE, the elevator will count down its departure schedule.
-
-//////////////
-
-// requires: jaunting library v14.0 or higher.
-//////////////
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-string JAUNT_COMMAND = "#jaunt#";
-    // command used to tell jaunt script to move object.
-//////////////
-
-//////////////
-
-// global variables and their default values...
-
-integer going_up = FALSE;
-    // remembers which direction the platform is moving.
-
-integer next_movement;
-    // when the lift should next move.  delayed for stations and
-    // when user chooses to delay take-off.
-
-//////////////
-
-float height_above_ground()
-{
-    vector position = llGetPos();
-    vector size = llGetAgentSize(llGetOwner()); 
-    return position.z - llGround(<0.0,0.0,0.0>) - size.z;
-}
-
-jaunt_to_target(vector target)
-{
-    llMessageLinked(LINK_THIS, JAUNT_HUFFWARE_ID, JAUNT_COMMAND, (string)target);
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        // initialize the next movement so elevator doesn't just zoom off.
-        next_movement = llGetUnixTime() + (integer)SLEEP_DURATION;
-        // we move at one second intervals due to our use of unix time,
-        // which has a resolution of seconds.
-        llSetTimerEvent(1.0);
-    }
-    
-//need commands, like start, or call to come down.
-// need elevator system that would call it.
-//  if elevator style deal, needs to not delay so silly like.
-//    when jaunting, go go go.
-    
-    timer()
-    {
-        integer time_now = llGetUnixTime();
-        // make sure it's time to do something.
-        if (time_now < next_movement) {
-            integer time_left = next_movement - time_now;
-            if ( (time_left <= 2) || !(time_left % COUNTDOWN_INTERVAL) ) {
-                if (WHISPER_COUNTDOWN) {
-//hmmm: abstract pluralizer out as separate function.
-                    string plural = "s";
-                    if (time_left == 1) plural = "";
-                    llWhisper(0, "Time remaining before departure: "
-                        + (string)time_left + " second" + plural + ".");
-                }
-            }
-            return;  // not time to move yet.
-        }
-        // set the next movement time to be without any delay, until we know better.
-        next_movement = llGetUnixTime();
-        // compute where we should jump to next.        
-        vector next_location = llGetPos();
-        // add in the appropriate amount to our height.
-        if (going_up) next_location += <0.0, 0.0, movement_per_cycle>;
-        else next_location -= <0.0, 0.0, movement_per_cycle>;
-        // check whether we've hit one of our extremes.
-        if (next_location.z >= maximum_height) {
-            going_up = FALSE;  // start going down.
-            next_movement = llGetUnixTime() + (integer)SLEEP_DURATION;
-            next_location.z = maximum_height;
-        } else if (next_location.z <= minimum_height + llGround(<0.0,0.0,0.0>)) {
-            going_up = TRUE;  // begin going up.
-            next_movement = llGetUnixTime() + (integer)SLEEP_DURATION;
-            next_location.z = minimum_height + llGround(<0.0,0.0,0.0>);
-        }
-        // now actually go to where we decided.
-        jaunt_to_target(next_location);
-    }
-
-    touch_start(integer total_number)
-    {
-        next_movement += (integer)PAUSE_DURATION;
-        llWhisper(0, "Your click delays departure by " + (string)PAUSE_DURATION + " seconds.");
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/uuid_shower_mat_v0.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/uuid_shower_mat_v0.3.lsl
new file mode 100755 (executable)
index 0000000..d9479ad
--- /dev/null
@@ -0,0 +1,24 @@
+
+// huffware script: uuid shower, by fred huffhines
+//
+// a simple script that shows an avatar their universally unique ID.
+//
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {}
+
+    touch_start(integer total_number)
+    {
+        llSay(0, "Hello " + llDetectedName(0) + ", your UUID is " + (string)llDetectedKey(0));
+    }
+}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/uuid_shower_mat_v0.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/uuid_shower_mat_v0.3.txt
deleted file mode 100755 (executable)
index d9479ad..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-
-// huffware script: uuid shower, by fred huffhines
-//
-// a simple script that shows an avatar their universally unique ID.
-//
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {}
-
-    touch_start(integer total_number)
-    {
-        llSay(0, "Hello " + llDetectedName(0) + ", your UUID is " + (string)llDetectedKey(0));
-    }
-}
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/vendor_sales_manager_v3.1.lsl b/huffware/huffotronic_tools_n_testers_v6.1/vendor_sales_manager_v3.1.lsl
new file mode 100755 (executable)
index 0000000..320bc71
--- /dev/null
@@ -0,0 +1,458 @@
+
+// huffware script: vendor sales manager, by fred huffhines.
+//
+// handles the vending of one set of items which are contained inside the vendor
+// object.  when the customer pays for it, they get a copy in a folder named after
+// the object, and the owner gets an instant message describing the purchase.
+//
+// parts of this script were gratefully snagged from Ilse's Basic Vendor version 1.3, by Ilse Mannonen.
+//
+// fred's changes are licensed by:
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// usage notes:
+//
+// the config notecard is hopefully pretty self explanatory.
+// here's an example config for a random gift vendor...
+//   price=<18, 37, 0>
+//   seller_name=gorp
+//   thank_you=Thank you very much fer your purchase!
+//   emails=foop@norgrufextorp.cog
+//   single=random
+//   text=Random Prize Machine\nPay the random price and get a random prize!
+//
+// here's an example config for a normal vendor (that gives out all of
+// the contents to a customer on purchase)...
+//   price=82
+//   seller_name=gorp
+//   thank_you=Thank you very much fer your purchase!
+//   emails=foop@norgrufextorp.cog
+//   text=Buy an anti-ape machine for your garage!
+//
+// the split notecard requires a set of lines in the format:
+//   KEY|PERCENT
+// for example: 0000000000bad|30 would give 30 percent of purchases to
+// the bogus key.  be sure to find out the real keys involved.
+
+// initial defaults; these need to be overridden by the notecard.
+integer price = 9999;
+string str_thank_you = "Default thank you message.  Thanks.";
+string seller_name = "Frodo's Rings";
+string emails = "";
+
+// if we're allowed to randomly charge in a range, then this records our range.
+integer lowest_price = 0;
+integer highest_price = 0;
+
+// variables for split notecard.
+integer splitline = 0;
+key splitrequestid;
+
+// variables for config notecard.
+integer configline = 0;
+key configrequestid;
+
+// keys and percentages that profits should be split with.
+list splitkeys;
+list splitpercents;
+
+// this is set to true if the vendor should select a single item
+// at random from the contents and give it to the customer.
+integer single_random_give = FALSE;
+
+list current_giving_list;  // if there is a transaction occurring, this has the contents to be given.
+
+float REPRICING_PERIOD = 20.0;  // how frequently we redo the price of the object, if it's random.
+
+// lets the potential customer know what is being sold.
+describe_product()
+{
+    if (lowest_price != 0)
+        llSay(0, "Cost is random and will be between L$" + (string)lowest_price
+            + " and L$" + (string)highest_price + ".");
+    else
+        llSay(0, "Cost is L$" + (string)price + ".");
+    if (single_random_give)
+        llSay(0, "This vendor is in random grab-bag mode; purchasers will receive one random object from the contents.");
+}
+
+// process the customer's attempt to hand us their money.
+take_their_moolah(key customer, integer amount)
+{
+    // check the amount they paid.
+    if ( (amount == price) || ( (lowest_price != 0) && (amount > lowest_price) ) ) {
+        integer worked = give_objects_appropriately(customer);
+        if (!worked) {
+            llSay(0, "Oh my, this is not good.  There were no objects left to give out.  We'll refund your money now.");
+            llGiveMoney(customer, amount);
+            return;
+        }
+
+        // thank the purchaser.
+        llSay(0, str_thank_you);
+        // IM the seller.
+        llInstantMessage(llGetOwner(), "Yay! " + llKey2Name(customer)
+            + " just paid me L$" + (string)amount
+            + " in " + llGetRegionName() + ".");
+        // do the split.
+        integer n;
+        for (n = 0; n < llGetListLength(splitkeys); n++) {
+            float percentage = llList2Float(splitpercents, n) / 100.0;
+            integer payout = llRound(price * percentage);
+            key payee = llList2Key(splitkeys, n);
+            llInstantMessage(llGetOwner(), "Paying L$" + (string)payout
+                + " to key " + (string)payee + " in commission.");
+            llGiveMoney(payee,payout);
+            string text_percentage = (string)((integer)(percentage * 1000.0) / 10);
+            llInstantMessage(payee, "Woot!  You have been paid a L$"
+                + (string)payout
+                + " (" + text_percentage + "%) commission for a sale in "
+                + llGetRegionName()
+                + "--customer name is " + llKey2Name(customer)
+                + ".");
+        }
+        // send out email alerts if there are any recipients.
+        list email_addrs = llParseString2List(emails, ["|"], []);
+        for (n = 0; n < llGetListLength(email_addrs); n++) {
+            string curr = llList2String(email_addrs, n);
+            llEmail(curr, llGetObjectName() + " made a sale in " + llGetRegionName(),
+                "Wheee, there was a sale in " + llGetRegionName() + " of these items "
+                + dump_list(current_giving_list) + " to a customer named "
+                + llKey2Name(customer) + ".");
+        }
+    } else {
+        // oops, something stupid.  give it all back.
+        llInstantMessage(customer, "I'm sorry, but you paid L$" + (string)amount + ", and this item costs only L$" + (string)price + ".  We'll refund your money right away.");
+        llGiveMoney(customer, amount);
+    }
+    
+    if (lowest_price != 0) {
+        // reset the timer to fire soon and change the price.
+        llSetTimerEvent(0.5);
+    }
+}
+  
+// hands out objects according to the configured process.
+integer give_objects_appropriately(key customer)
+{
+    current_giving_list = [];  // clear out last gifts.
+    if (!single_random_give) {
+        // this mode is only for the normal non random picker.
+        // if it's right, give everything but scripts and config notecards.
+        integer m;
+        for (m = 0; m < llGetInventoryNumber(INVENTORY_ALL); m++) {
+            string itemname = llGetInventoryName(INVENTORY_ALL, m);
+            if (llGetInventoryType(itemname) == INVENTORY_NOTECARD) {
+                //only add notecards if they don't start with ~
+                if (llGetSubString(itemname, 0, 0) != "~") {
+                    current_giving_list += [itemname];
+                }
+            } else {
+                if (llGetInventoryType(itemname) != INVENTORY_SCRIPT) {
+                    current_giving_list += [itemname];
+                }
+            }
+        }
+    } else {
+        // aha, the freaky random gift giving model.
+        if (llGetInventoryNumber(INVENTORY_OBJECT) >= 1) {
+            // we made sure we have something to give out.
+            integer which = (integer)randomize_within_range(0, llGetInventoryNumber(INVENTORY_OBJECT) - 1, FALSE);
+            if (which >= 0) {
+                current_giving_list += [ llGetInventoryName(INVENTORY_OBJECT, which) ];
+            }
+        }
+    }
+    
+//llOwnerSay("about to give out " + (string)current_giving_list);
+    if (llGetListLength(current_giving_list) > 0) {
+        if (single_random_give)
+            llGiveInventory(customer, llList2String(current_giving_list, 0));
+        else
+            llGiveInventoryList(customer, seller_name + " - " + llGetObjectName(), current_giving_list);
+        return TRUE;
+    } else return FALSE;  // oops.
+}
+
+// a wrapper for setting the object's text, but handling carriage returns.
+set_text(string object_label)
+{
+    // reset the label to a decorated version of object name if it was default.
+    if (object_label == "default") object_label = llGetObjectName();
+    integer indy;
+    integer keep_going = TRUE;
+    while (keep_going) {
+        indy = find_substring(object_label, "\\n");
+        if (indy < 0) {
+            keep_going = FALSE;
+        } else {
+            object_label = llGetSubString(object_label, 0, indy - 1)
+                + "\n" + llGetSubString(object_label, indy + 2, -1);
+        }
+    }
+//log_it("setting text: " + object_label);
+    llSetText(object_label, <0.4, 0.7, 0.95>, 1.0);
+}
+
+// eats config items that are read from the notecard.
+process_configuration_items(string data)
+{
+    string token = llList2String(llParseString2List(data, ["="], []), 0);
+    string value = llList2String(llParseString2List(data, ["="], []), 1);
+    if (token == "price") {
+        if (is_prefix(value, "<")) {
+            // we have a random price range definition.
+            vector ranger = (vector)value;
+            lowest_price = (integer)ranger.x;
+            highest_price = (integer)ranger.y;
+            price = lowest_price;
+            // we run a timer to keep the price fluctuating for the user.
+            if (lowest_price != 0) {
+                // zap the timer event really soon.
+                llSetTimerEvent(0.5);
+            }
+        } else {
+            // this is hopefully a simple price definition.
+            price = (integer)value;
+            lowest_price = 0;  // reset so no one gets wrong ideas.
+        }
+        if (price == 0) {
+            llOwnerSay("Failure in setting price; object will be defective until config is fixed.");
+        } else {
+            llSetPayPrice(PAY_HIDE, [price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
+            llMessageLinked(LINK_SET, price, "price", NULL_KEY);
+            describe_product();
+        }
+    } else if (token == "thank_you") {
+        str_thank_you = value;
+    } else if (token == "seller_name") {
+        seller_name = value;
+    } else if (token == "emails") {
+        emails = value;
+    } else if (token == "single") {
+        if (value == "random") {
+            single_random_give = TRUE;
+            describe_product();
+        }
+    } else if (token == "text") {
+        set_text(value);
+//        llSetText(value, <.4, .9, .7>, 1.0);        
+    }
+    configline++;
+    configrequestid = llGetNotecardLine("~CONFIG", configline);
+}
+
+//////////////
+// from hufflets...
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns a printable form of the list.
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = 0; i < len; i++) {
+        string next_line = llList2String(to_show, i);
+        if (find_substring(next_line, " ") >= 0) {
+            // this guy has a space in it, so quote it.
+            next_line = "'" + next_line + "'";
+        }
+        text += next_line;
+        if (i < len - 1) text += " ";
+    }
+    return text;
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();  // make sure newest addition is only version of script.
+        splitrequestid = llGetNotecardLine("~SPLIT", splitline);
+        configrequestid = llGetNotecardLine("~CONFIG", configline);
+        llSetPayPrice(PAY_HIDE, [price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
+        llSetText("garp", <0, 0, 0>, 0);
+    }
+    
+    on_rez(integer start_param) { llResetScript(); }
+        
+    timer() {
+        llSetTimerEvent(0);
+        price = (integer)randomize_within_range(lowest_price, highest_price, FALSE);
+        llSetPayPrice(PAY_HIDE, [price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
+        llSetTimerEvent(REPRICING_PERIOD);
+    }    
+            
+    money(key customer, integer amount) { take_their_moolah(customer, amount); }
+
+    // restart if something was added to the vendor.    
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) { llSleep(3.14159265358); llResetScript(); }
+    }
+    
+    touch_start(integer total_number)
+    {
+        // give the first non-config notecard.
+        integer n;
+        for (n = 0; n < llGetInventoryNumber(INVENTORY_NOTECARD); n++) {
+            if (llGetSubString(llGetInventoryName(INVENTORY_NOTECARD, n), 0, 0) != "~") {
+                llGiveInventory(llDetectedKey(0), llGetInventoryName(INVENTORY_NOTECARD, n));
+                return;
+            }
+        }
+        describe_product();
+    }    
+
+    // read the two configuration notecards.
+    dataserver(key queryid, string data)
+    {
+        if ( (queryid == splitrequestid) && (data != EOF) ) {
+            list tmp = llParseString2List(data, ["|"], [""]);
+            if (llGetListLength(tmp) > 1) {
+                splitpercents += llList2Integer(tmp,1);
+                splitkeys += llList2Key(tmp,0);
+                if (splitline == 0) {
+                    llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
+                }
+                splitline++;
+                splitrequestid = llGetNotecardLine("~SPLIT",splitline);                
+            }
+        } else if ( (queryid == configrequestid) && (data != EOF) ) {
+            process_configuration_items(data);
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/vendor_sales_manager_v3.1.txt b/huffware/huffotronic_tools_n_testers_v6.1/vendor_sales_manager_v3.1.txt
deleted file mode 100755 (executable)
index 320bc71..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-
-// huffware script: vendor sales manager, by fred huffhines.
-//
-// handles the vending of one set of items which are contained inside the vendor
-// object.  when the customer pays for it, they get a copy in a folder named after
-// the object, and the owner gets an instant message describing the purchase.
-//
-// parts of this script were gratefully snagged from Ilse's Basic Vendor version 1.3, by Ilse Mannonen.
-//
-// fred's changes are licensed by:
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// usage notes:
-//
-// the config notecard is hopefully pretty self explanatory.
-// here's an example config for a random gift vendor...
-//   price=<18, 37, 0>
-//   seller_name=gorp
-//   thank_you=Thank you very much fer your purchase!
-//   emails=foop@norgrufextorp.cog
-//   single=random
-//   text=Random Prize Machine\nPay the random price and get a random prize!
-//
-// here's an example config for a normal vendor (that gives out all of
-// the contents to a customer on purchase)...
-//   price=82
-//   seller_name=gorp
-//   thank_you=Thank you very much fer your purchase!
-//   emails=foop@norgrufextorp.cog
-//   text=Buy an anti-ape machine for your garage!
-//
-// the split notecard requires a set of lines in the format:
-//   KEY|PERCENT
-// for example: 0000000000bad|30 would give 30 percent of purchases to
-// the bogus key.  be sure to find out the real keys involved.
-
-// initial defaults; these need to be overridden by the notecard.
-integer price = 9999;
-string str_thank_you = "Default thank you message.  Thanks.";
-string seller_name = "Frodo's Rings";
-string emails = "";
-
-// if we're allowed to randomly charge in a range, then this records our range.
-integer lowest_price = 0;
-integer highest_price = 0;
-
-// variables for split notecard.
-integer splitline = 0;
-key splitrequestid;
-
-// variables for config notecard.
-integer configline = 0;
-key configrequestid;
-
-// keys and percentages that profits should be split with.
-list splitkeys;
-list splitpercents;
-
-// this is set to true if the vendor should select a single item
-// at random from the contents and give it to the customer.
-integer single_random_give = FALSE;
-
-list current_giving_list;  // if there is a transaction occurring, this has the contents to be given.
-
-float REPRICING_PERIOD = 20.0;  // how frequently we redo the price of the object, if it's random.
-
-// lets the potential customer know what is being sold.
-describe_product()
-{
-    if (lowest_price != 0)
-        llSay(0, "Cost is random and will be between L$" + (string)lowest_price
-            + " and L$" + (string)highest_price + ".");
-    else
-        llSay(0, "Cost is L$" + (string)price + ".");
-    if (single_random_give)
-        llSay(0, "This vendor is in random grab-bag mode; purchasers will receive one random object from the contents.");
-}
-
-// process the customer's attempt to hand us their money.
-take_their_moolah(key customer, integer amount)
-{
-    // check the amount they paid.
-    if ( (amount == price) || ( (lowest_price != 0) && (amount > lowest_price) ) ) {
-        integer worked = give_objects_appropriately(customer);
-        if (!worked) {
-            llSay(0, "Oh my, this is not good.  There were no objects left to give out.  We'll refund your money now.");
-            llGiveMoney(customer, amount);
-            return;
-        }
-
-        // thank the purchaser.
-        llSay(0, str_thank_you);
-        // IM the seller.
-        llInstantMessage(llGetOwner(), "Yay! " + llKey2Name(customer)
-            + " just paid me L$" + (string)amount
-            + " in " + llGetRegionName() + ".");
-        // do the split.
-        integer n;
-        for (n = 0; n < llGetListLength(splitkeys); n++) {
-            float percentage = llList2Float(splitpercents, n) / 100.0;
-            integer payout = llRound(price * percentage);
-            key payee = llList2Key(splitkeys, n);
-            llInstantMessage(llGetOwner(), "Paying L$" + (string)payout
-                + " to key " + (string)payee + " in commission.");
-            llGiveMoney(payee,payout);
-            string text_percentage = (string)((integer)(percentage * 1000.0) / 10);
-            llInstantMessage(payee, "Woot!  You have been paid a L$"
-                + (string)payout
-                + " (" + text_percentage + "%) commission for a sale in "
-                + llGetRegionName()
-                + "--customer name is " + llKey2Name(customer)
-                + ".");
-        }
-        // send out email alerts if there are any recipients.
-        list email_addrs = llParseString2List(emails, ["|"], []);
-        for (n = 0; n < llGetListLength(email_addrs); n++) {
-            string curr = llList2String(email_addrs, n);
-            llEmail(curr, llGetObjectName() + " made a sale in " + llGetRegionName(),
-                "Wheee, there was a sale in " + llGetRegionName() + " of these items "
-                + dump_list(current_giving_list) + " to a customer named "
-                + llKey2Name(customer) + ".");
-        }
-    } else {
-        // oops, something stupid.  give it all back.
-        llInstantMessage(customer, "I'm sorry, but you paid L$" + (string)amount + ", and this item costs only L$" + (string)price + ".  We'll refund your money right away.");
-        llGiveMoney(customer, amount);
-    }
-    
-    if (lowest_price != 0) {
-        // reset the timer to fire soon and change the price.
-        llSetTimerEvent(0.5);
-    }
-}
-  
-// hands out objects according to the configured process.
-integer give_objects_appropriately(key customer)
-{
-    current_giving_list = [];  // clear out last gifts.
-    if (!single_random_give) {
-        // this mode is only for the normal non random picker.
-        // if it's right, give everything but scripts and config notecards.
-        integer m;
-        for (m = 0; m < llGetInventoryNumber(INVENTORY_ALL); m++) {
-            string itemname = llGetInventoryName(INVENTORY_ALL, m);
-            if (llGetInventoryType(itemname) == INVENTORY_NOTECARD) {
-                //only add notecards if they don't start with ~
-                if (llGetSubString(itemname, 0, 0) != "~") {
-                    current_giving_list += [itemname];
-                }
-            } else {
-                if (llGetInventoryType(itemname) != INVENTORY_SCRIPT) {
-                    current_giving_list += [itemname];
-                }
-            }
-        }
-    } else {
-        // aha, the freaky random gift giving model.
-        if (llGetInventoryNumber(INVENTORY_OBJECT) >= 1) {
-            // we made sure we have something to give out.
-            integer which = (integer)randomize_within_range(0, llGetInventoryNumber(INVENTORY_OBJECT) - 1, FALSE);
-            if (which >= 0) {
-                current_giving_list += [ llGetInventoryName(INVENTORY_OBJECT, which) ];
-            }
-        }
-    }
-    
-//llOwnerSay("about to give out " + (string)current_giving_list);
-    if (llGetListLength(current_giving_list) > 0) {
-        if (single_random_give)
-            llGiveInventory(customer, llList2String(current_giving_list, 0));
-        else
-            llGiveInventoryList(customer, seller_name + " - " + llGetObjectName(), current_giving_list);
-        return TRUE;
-    } else return FALSE;  // oops.
-}
-
-// a wrapper for setting the object's text, but handling carriage returns.
-set_text(string object_label)
-{
-    // reset the label to a decorated version of object name if it was default.
-    if (object_label == "default") object_label = llGetObjectName();
-    integer indy;
-    integer keep_going = TRUE;
-    while (keep_going) {
-        indy = find_substring(object_label, "\\n");
-        if (indy < 0) {
-            keep_going = FALSE;
-        } else {
-            object_label = llGetSubString(object_label, 0, indy - 1)
-                + "\n" + llGetSubString(object_label, indy + 2, -1);
-        }
-    }
-//log_it("setting text: " + object_label);
-    llSetText(object_label, <0.4, 0.7, 0.95>, 1.0);
-}
-
-// eats config items that are read from the notecard.
-process_configuration_items(string data)
-{
-    string token = llList2String(llParseString2List(data, ["="], []), 0);
-    string value = llList2String(llParseString2List(data, ["="], []), 1);
-    if (token == "price") {
-        if (is_prefix(value, "<")) {
-            // we have a random price range definition.
-            vector ranger = (vector)value;
-            lowest_price = (integer)ranger.x;
-            highest_price = (integer)ranger.y;
-            price = lowest_price;
-            // we run a timer to keep the price fluctuating for the user.
-            if (lowest_price != 0) {
-                // zap the timer event really soon.
-                llSetTimerEvent(0.5);
-            }
-        } else {
-            // this is hopefully a simple price definition.
-            price = (integer)value;
-            lowest_price = 0;  // reset so no one gets wrong ideas.
-        }
-        if (price == 0) {
-            llOwnerSay("Failure in setting price; object will be defective until config is fixed.");
-        } else {
-            llSetPayPrice(PAY_HIDE, [price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
-            llMessageLinked(LINK_SET, price, "price", NULL_KEY);
-            describe_product();
-        }
-    } else if (token == "thank_you") {
-        str_thank_you = value;
-    } else if (token == "seller_name") {
-        seller_name = value;
-    } else if (token == "emails") {
-        emails = value;
-    } else if (token == "single") {
-        if (value == "random") {
-            single_random_give = TRUE;
-            describe_product();
-        }
-    } else if (token == "text") {
-        set_text(value);
-//        llSetText(value, <.4, .9, .7>, 1.0);        
-    }
-    configline++;
-    configrequestid = llGetNotecardLine("~CONFIG", configline);
-}
-
-//////////////
-// from hufflets...
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns a printable form of the list.
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = 0; i < len; i++) {
-        string next_line = llList2String(to_show, i);
-        if (find_substring(next_line, " ") >= 0) {
-            // this guy has a space in it, so quote it.
-            next_line = "'" + next_line + "'";
-        }
-        text += next_line;
-        if (i < len - 1) text += " ";
-    }
-    return text;
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();  // make sure newest addition is only version of script.
-        splitrequestid = llGetNotecardLine("~SPLIT", splitline);
-        configrequestid = llGetNotecardLine("~CONFIG", configline);
-        llSetPayPrice(PAY_HIDE, [price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
-        llSetText("garp", <0, 0, 0>, 0);
-    }
-    
-    on_rez(integer start_param) { llResetScript(); }
-        
-    timer() {
-        llSetTimerEvent(0);
-        price = (integer)randomize_within_range(lowest_price, highest_price, FALSE);
-        llSetPayPrice(PAY_HIDE, [price, PAY_HIDE, PAY_HIDE, PAY_HIDE]);
-        llSetTimerEvent(REPRICING_PERIOD);
-    }    
-            
-    money(key customer, integer amount) { take_their_moolah(customer, amount); }
-
-    // restart if something was added to the vendor.    
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) { llSleep(3.14159265358); llResetScript(); }
-    }
-    
-    touch_start(integer total_number)
-    {
-        // give the first non-config notecard.
-        integer n;
-        for (n = 0; n < llGetInventoryNumber(INVENTORY_NOTECARD); n++) {
-            if (llGetSubString(llGetInventoryName(INVENTORY_NOTECARD, n), 0, 0) != "~") {
-                llGiveInventory(llDetectedKey(0), llGetInventoryName(INVENTORY_NOTECARD, n));
-                return;
-            }
-        }
-        describe_product();
-    }    
-
-    // read the two configuration notecards.
-    dataserver(key queryid, string data)
-    {
-        if ( (queryid == splitrequestid) && (data != EOF) ) {
-            list tmp = llParseString2List(data, ["|"], [""]);
-            if (llGetListLength(tmp) > 1) {
-                splitpercents += llList2Integer(tmp,1);
-                splitkeys += llList2Key(tmp,0);
-                if (splitline == 0) {
-                    llRequestPermissions(llGetOwner(), PERMISSION_DEBIT);
-                }
-                splitline++;
-                splitrequestid = llGetNotecardLine("~SPLIT",splitline);                
-            }
-        } else if ( (queryid == configrequestid) && (data != EOF) ) {
-            process_configuration_items(data);
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/zap_updater_from_elevators_v1.3.lsl b/huffware/huffotronic_tools_n_testers_v6.1/zap_updater_from_elevators_v1.3.lsl
new file mode 100755 (executable)
index 0000000..6dee724
--- /dev/null
@@ -0,0 +1,187 @@
+
+// huffware script: zap updater from elevators, by fred huffhines
+//
+// this script is an evil little assassin that is supposed to remove the updater
+// script from the objects it's added to.  it should not remove that script from
+// any huffotronic devices though.
+// this is an attempt to quell some SL stability problems due to some seeming
+// combination of numbers of objects and numbers of scripts.
+// we hope to be able to add the updater back in automatically later because the
+// script pin should still be set.  let's see if osgrid has that behavior the same
+// as second life did.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+
+// from hufflets...
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// returns true if this object is a huffotronic updater of some sort.
+integer inside_of_updater()
+{
+    return find_substring(llGetObjectName(), "huffotronic") >= 0;
+}
+
+// stops all the scripts besides this one.
+knock_around_other_scripts(integer running_state)
+{
+    integer indy;
+    integer insider = inside_of_updater();
+    string self_script = llGetScriptName();
+    // we set all other scripts to the running state requested.
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if ( (curr_script != self_script)
+            && (!insider || matches_server_script(curr_script)) ) {
+            // this one seems ripe for being set to the state requested.
+            llSetScriptState(curr_script, running_state);
+        }
+    }
+}
+
+string SERVER_SCRIPT = "huffotronic update server";
+    // the prefix of our server script that hands out updates.
+
+// returns true if a script is a version of our update server.
+integer matches_server_script(string to_check)
+{
+    return is_prefix(to_check, SERVER_SCRIPT);
+}
+
+// end hufflets.
+//////////////
+
+default
+{
+    state_entry()
+    {
+        auto_retire();
+        if (inside_of_updater()) return;  // do nothing else.
+        
+        llWhisper(0, "hello, i'm jeeves.  pleased to meet you.");
+        llSleep(32);
+        
+        string gotta_zap = "huff-update client v";
+        integer i;
+        for (i = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; i >= 0; i--) {
+            string cur = llGetInventoryName(INVENTORY_SCRIPT, i);
+            if (is_prefix(cur, gotta_zap)) {
+                llWhisper(0, "i, jeeves, will now clean out this script: " + cur);
+                llRemoveInventory(cur);
+            }
+        }
+        llSleep(14);
+        knock_around_other_scripts(TRUE);
+        llSleep(4);
+        llWhisper(0, "i'm sorry to say sir that i now must bid you adieu, as i am removing myself from the world.");
+        llSleep(1);
+        llRemoveInventory(llGetScriptName());
+    }
+}
+
diff --git a/huffware/huffotronic_tools_n_testers_v6.1/zap_updater_from_elevators_v1.3.txt b/huffware/huffotronic_tools_n_testers_v6.1/zap_updater_from_elevators_v1.3.txt
deleted file mode 100755 (executable)
index 6dee724..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-
-// huffware script: zap updater from elevators, by fred huffhines
-//
-// this script is an evil little assassin that is supposed to remove the updater
-// script from the objects it's added to.  it should not remove that script from
-// any huffotronic devices though.
-// this is an attempt to quell some SL stability problems due to some seeming
-// combination of numbers of objects and numbers of scripts.
-// we hope to be able to add the updater back in automatically later because the
-// script pin should still be set.  let's see if osgrid has that behavior the same
-// as second life did.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-
-// from hufflets...
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// returns true if this object is a huffotronic updater of some sort.
-integer inside_of_updater()
-{
-    return find_substring(llGetObjectName(), "huffotronic") >= 0;
-}
-
-// stops all the scripts besides this one.
-knock_around_other_scripts(integer running_state)
-{
-    integer indy;
-    integer insider = inside_of_updater();
-    string self_script = llGetScriptName();
-    // we set all other scripts to the running state requested.
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if ( (curr_script != self_script)
-            && (!insider || matches_server_script(curr_script)) ) {
-            // this one seems ripe for being set to the state requested.
-            llSetScriptState(curr_script, running_state);
-        }
-    }
-}
-
-string SERVER_SCRIPT = "huffotronic update server";
-    // the prefix of our server script that hands out updates.
-
-// returns true if a script is a version of our update server.
-integer matches_server_script(string to_check)
-{
-    return is_prefix(to_check, SERVER_SCRIPT);
-}
-
-// end hufflets.
-//////////////
-
-default
-{
-    state_entry()
-    {
-        auto_retire();
-        if (inside_of_updater()) return;  // do nothing else.
-        
-        llWhisper(0, "hello, i'm jeeves.  pleased to meet you.");
-        llSleep(32);
-        
-        string gotta_zap = "huff-update client v";
-        integer i;
-        for (i = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; i >= 0; i--) {
-            string cur = llGetInventoryName(INVENTORY_SCRIPT, i);
-            if (is_prefix(cur, gotta_zap)) {
-                llWhisper(0, "i, jeeves, will now clean out this script: " + cur);
-                llRemoveInventory(cur);
-            }
-        }
-        llSleep(14);
-        knock_around_other_scripts(TRUE);
-        llSleep(4);
-        llWhisper(0, "i'm sorry to say sir that i now must bid you adieu, as i am removing myself from the world.");
-        llSleep(1);
-        llRemoveInventory(llGetScriptName());
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/FPS_color_changer_v2.4.lsl b/huffware/huffotronic_updater_freebie_v5.3/FPS_color_changer_v2.4.lsl
new file mode 100755 (executable)
index 0000000..b7be286
--- /dev/null
@@ -0,0 +1,156 @@
+
+// huffware script: FPS color changer, by fred huffhines
+//
+// a freebie script by eltee statosky supplied inspiration for this script.
+// we have re-used his color scheme, but rewritten this for our needs.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer SHOW_TITLE = FALSE;
+    // if this is true, a title is set above the object.
+
+//hmmm: this max fps value used to compute a percentage may be totally bogus.
+//  highest i've seen is 55 or so in opensim.  used to be highest in second life
+//  was 45 or something.  seems unknowable so far.
+float MAX_SIM_FPS = 60.0;
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();  // make sure newest addition is only version of script.
+        llSetTimerEvent(4.0);
+    }
+    
+    timer() {
+        float fps = llGetRegionFPS();
+        vector sim_color;
+        if (fps > 50) sim_color = <0.5, 1.0, 0.5>;   
+        else if (fps > 40) sim_color = <0.75, 0.75, 0>;
+        else if (fps > 30) sim_color = <1.0, 0.5, 0.5>;
+        else sim_color = <0.5, 0.0, 0.0>;
+        llSetColor(sim_color, ALL_SIDES);
+        if (SHOW_TITLE) {
+            integer left_part = (integer)fps;  // left of decimal point.
+            integer right_part = (integer)(llRound((fps - (integer)fps) * 10.0));
+            float simplified_fps = (float)left_part + ((float)right_part / 10.0);
+            llSetText(llGetRegionName() + " "
+                + (string)left_part + "." + (string)right_part
+                + " FPS ("
+                + (string)llRound(simplified_fps / MAX_SIM_FPS * 100.0)
+                + "%)",
+                sim_color, 1.0);
+        } else {
+            llSetText("--", <0.0, 0.0, 0.0>, 0.0);
+        }
+    }
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/FPS_color_changer_v2.4.txt b/huffware/huffotronic_updater_freebie_v5.3/FPS_color_changer_v2.4.txt
deleted file mode 100755 (executable)
index b7be286..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-
-// huffware script: FPS color changer, by fred huffhines
-//
-// a freebie script by eltee statosky supplied inspiration for this script.
-// we have re-used his color scheme, but rewritten this for our needs.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer SHOW_TITLE = FALSE;
-    // if this is true, a title is set above the object.
-
-//hmmm: this max fps value used to compute a percentage may be totally bogus.
-//  highest i've seen is 55 or so in opensim.  used to be highest in second life
-//  was 45 or something.  seems unknowable so far.
-float MAX_SIM_FPS = 60.0;
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();  // make sure newest addition is only version of script.
-        llSetTimerEvent(4.0);
-    }
-    
-    timer() {
-        float fps = llGetRegionFPS();
-        vector sim_color;
-        if (fps > 50) sim_color = <0.5, 1.0, 0.5>;   
-        else if (fps > 40) sim_color = <0.75, 0.75, 0>;
-        else if (fps > 30) sim_color = <1.0, 0.5, 0.5>;
-        else sim_color = <0.5, 0.0, 0.0>;
-        llSetColor(sim_color, ALL_SIDES);
-        if (SHOW_TITLE) {
-            integer left_part = (integer)fps;  // left of decimal point.
-            integer right_part = (integer)(llRound((fps - (integer)fps) * 10.0));
-            float simplified_fps = (float)left_part + ((float)right_part / 10.0);
-            llSetText(llGetRegionName() + " "
-                + (string)left_part + "." + (string)right_part
-                + " FPS ("
-                + (string)llRound(simplified_fps / MAX_SIM_FPS * 100.0)
-                + "%)",
-                sim_color, 1.0);
-        } else {
-            llSetText("--", <0.0, 0.0, 0.0>, 0.0);
-        }
-    }
-}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/FreeView_v1.8.lsl b/huffware/huffotronic_updater_freebie_v5.3/FreeView_v1.8.lsl
new file mode 100755 (executable)
index 0000000..bb809fd
--- /dev/null
@@ -0,0 +1,834 @@
+
+// huffware script: freeview modified by fred huffhines (see original license below).
+//
+// my changes are licensed this way:
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+// fred's changes include:
+// + assorted tweaks that i have since forgotten the details about.
+// + set the freeview to startup as a picture viewer, since that's my most common usage.
+
+//////////////
+// original author info and licensing:
+//FreeView 1.2 WebGuide (revision 4) - By CrystalShard Foo
+//Multifunctional Picture viewer and Video control script with webguide support
+//This script is distributed for free and must stay that way. 
+//      *** If you wish to give/sell a product using this script,  ***
+//      ***     THEN THE SCRIPT MUST REMAIN FULL-PERM AND FREE.    ***
+//      ***   Failure to do so will REVOKE your right to use it!   ***
+//Help for using this script can be obtained at: http://www.slguide.com/help
+//Feel free to modify this script and post your improvement. Leave the credits intact but feel free to add your name at its bottom.
+//Whats new:
+//- Now using FULL_BRIGHT instead of PRIM_MATERIAL_LIGHT for the screen display
+//- Added an ownership-change code to handle cases where FreeView gets deeded to group post Video Init.
+//- Renamed WebGuide to TV-Guide to reflect what this thing does better.
+//- Added a 'Fix Scale' button to Picture mode to help against user texture-scale changes.
+//- Additional minor help-tips and code improvements
+//Enjoy!
+//////////////
+
+
+//Constants
+integer PICTURE_ROTATION_TIMER = 30;   //In whole seconds
+
+integer DISPLAY_ON_SIDE = ALL_SIDES; //Change this to change where the image will be displayed
+
+key VIDEO_DEFAULT = "71b8ff26-087d-5f44-285b-d38df2e11a81";  //Test pattern - Used as default video texture when one is missing in parcel media
+key BLANK = "5748decc-f629-461c-9a36-a35a221fe21f"; //Blank texture - Used when there are no textures to display in Picture mode
+string NOTECARD = "bookmarks";  //Used to host URL bookmarks for video streams
+
+integer VIDEO_BRIGHT = TRUE;    //FULL_BRIGHT status for Video
+integer PICTURE_BRIGHT = TRUE;  //FULL_BRIGHT status for Picture
+
+integer REMOTE_CHANNEL = 9238742;
+
+integer EXTERNAL_TOUCH_CHANNEL = 1327;
+    // used by other prims to tell the viewer prim that the avatar has clicked on them.
+
+integer mode = 0;           //Freeview mode.
+                            //Mode 0 - Power off
+                            //Mode 1 - Picture viewer
+                            //Mode 2 - Video
+
+integer listenHandle = -1;      //Dialog menu listen handler
+integer listenUrl = -1;         //listen handler for channel 1 for when a URL is being added
+integer listenTimer = -1;       //Timer variable for removing all listeners after 2 minutes of listener inactivity
+integer listenRemote = -1;      //listen handler for the remote during initial setup
+integer encryption = 0;
+integer numberofnotecardlines = 0;  //Stores the current number of detected notecard lines.
+integer notecardline = 0;       //Current notecard line
+
+integer loop_image = FALSE;     //Are we looping pictures with a timer? (picture mode)
+integer current_texture = 0;    //Current texture number in inventory being displayed (picture mode)
+integer chan;                   //llDialog listen channel
+integer notecardcheck = 0;
+key video_texture;              //Currently used video display texture for parcel media stream
+
+string moviename;
+string tempmoviename;
+key notecardkey = NULL_KEY;
+key tempuser;                   //Temp key storge variable
+string tempurl;                 //Temp string storge variable
+
+integer isGroup = TRUE;
+key groupcheck = NULL_KEY;
+key last_owner;
+key XML_channel;
+
+pictures()      //Change mode to Picture Viewer
+{
+    //Initilize variables
+    
+    //Change prim to Light material while coloring face 0 black to prevent light-lag generation.
+    llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, PICTURE_BRIGHT]);
+
+    integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
+     
+    if(check == 0)
+    {
+        report("No pictures found.");
+        llSetTexture(BLANK,DISPLAY_ON_SIDE);
+        return;
+    }
+    else    
+        if(current_texture > check)
+            //Set to first texture if available
+            current_texture = 0;
+            
+    display_texture(current_texture);
+}
+
+video()         //Change mode to Video
+{
+    //Change prim to Light material while coloring face 0 black to prevent light-lag generation.
+    llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, VIDEO_BRIGHT, PRIM_TEXTURE, DISPLAY_ON_SIDE, "62dc73ca-265f-7ca0-0453-e2a6aa60bb6f", llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]);
+    
+    report("Video mode"+moviename+": Stopped");
+    if(finditem(NOTECARD) != -1)
+        tempuser = llGetNumberOfNotecardLines(NOTECARD);
+    video_texture = llList2Key(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_TEXTURE]),0);
+    if(video_texture == NULL_KEY)
+    {
+        video_texture = VIDEO_DEFAULT;
+        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_TEXTURE,VIDEO_DEFAULT]);
+        llSay(0,"No parcel media texture found. Setting texture to default: "+(string)VIDEO_DEFAULT);
+        if(llGetLandOwnerAt(llGetPos()) != llGetOwner())
+            llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner.");
+    }
+    
+    llSetTexture(video_texture,DISPLAY_ON_SIDE);
+}
+
+off()
+{
+    report("Click to power on.");
+    llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_LOW, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <0.1,0.1,0.1>, 1.0,PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, FALSE, PRIM_TEXTURE, DISPLAY_ON_SIDE, BLANK, llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]);
+}
+
+integer finditem(string name)   //Finds and returns an item's inventory number
+{
+    integer i;
+    for(i=0;i<llGetInventoryNumber(INVENTORY_NOTECARD);i++)
+        if(llGetInventoryName(INVENTORY_NOTECARD,i) == NOTECARD)
+            return i;
+    return -1;
+}
+
+seturl(string url, key id)  //Set parcel media URL
+{
+    if(mode != 2)
+    {
+        video();
+        mode = 2;
+    }
+    moviename = tempmoviename;
+    if(moviename)
+        moviename = " ["+moviename+"]";
+    tempmoviename = "";
+    string oldurl = llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0);
+    if(oldurl != "")
+        llOwnerSay("Setting new media URL. The old URL was: "+oldurl);
+
+    llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,url]);
+    if(id!=NULL_KEY)
+        menu(id);
+    else
+    {
+        report("Video mode"+moviename+": Playing");
+        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
+    }
+       
+    if(isGroup)
+        llSay(0,"New media URL set.");
+    else
+        llOwnerSay("New media URL set: "+url);
+}
+
+string mediatype(string ext)    //Returns a string stating the filetype of a file based on file extension
+{
+    ext = llToLower(ext);
+    if(ext == "swf")
+        return "Flash";
+    if(ext == "mov" || ext == "avi" || ext == "mpg" || ext == "mpeg" || ext == "smil")
+        return "Video";
+    if(ext == "jpg" || ext == "mpeg" || ext == "gif" || ext == "png" || ext == "pict" || ext == "tga" || ext == "tiff" || ext == "sgi" || ext == "bmp")
+        return "Image";
+    if(ext == "txt")
+        return "Text";
+    if(ext == "mp3" || ext == "wav")
+        return "Audio";
+    return "Unknown";
+}
+
+browse(key id)      //Image browser function for picture viewer mode
+{
+    integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
+    string header;
+    if(check > 0)
+        header = "("+(string)(current_texture+1)+"/"+(string)check+") "+llGetInventoryName(INVENTORY_TEXTURE,current_texture);
+    else
+        header = "No pictures found.";
+    llDialog(id,"** Monitor Control **\n Picture Viewer mode\n- Image browser\n- "+header,["Back","Next","Menu"],chan);
+    extendtimer();
+}
+
+report(string str)
+{
+    llSetObjectDesc(str);
+}
+
+extendtimer()       //Add another 2 minute to the Listen Removal timer (use when a Listen event is triggered)
+{
+    if(listenHandle == -1)
+        listenHandle = llListen(chan,"","","");
+    listenTimer = (integer)llGetTime() + 120;
+    if(loop_image == FALSE)
+        llSetTimerEvent(45);
+}
+
+config(key id)      //Configuration menu
+{
+    extendtimer();
+    llDialog(id,"Current media URL:\n"+llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0)+"\nTip: If the picture is abit off, try 'Align ON'",["Set URL","Align ON","Align OFF","Menu","Set Remote"],chan);
+}
+
+tell_remote(string str)
+{
+    llShout(REMOTE_CHANNEL,llXorBase64Strings(llStringToBase64((string)encryption + str), llStringToBase64((string)encryption)));
+}
+
+menu(key id)        //Dialog menus for all 3 modes
+{
+    list buttons = [];
+    string title = "** Monitor control **";
+    
+    extendtimer();
+
+    if(mode != 0)
+    {
+        if(mode == 1)       //Pictures menu
+        {
+            title+="\n  Picture Viewer mode";
+            buttons+=["Browse"];
+            if(loop_image == FALSE)
+                buttons+=["Loop"];
+            else
+                buttons+=["Unloop"];
+            buttons+=["Video","Power off","Help","Fix scale"];
+        }
+        else                //Video menu
+        {
+            title+="\n Video display mode\n"+moviename+"\nTip:\nClick 'TV Guide' to view the Online bookmarks.";
+            buttons+=["Pictures","Configure","Power off","Loop","Unload","Help","Play","Stop","Pause","TV Guide","Bookmarks","Set URL"];
+        }
+    }
+    else
+        buttons += ["Pictures","Video","Help"];
+    
+    llDialog(id,title,buttons,chan);
+}
+
+display_texture(integer check)  //Display texture and set name in description (picture mode)
+{                               //"Check" holds the number of textures in contents. The function uses "current_texture" to display.
+    string name = llGetInventoryName(INVENTORY_TEXTURE,current_texture);
+    llSetTexture(name,DISPLAY_ON_SIDE);
+    report("Showing picture: "+name+" ("+(string)(current_texture+1)+"/"+(string)check+")");
+}
+    
+
+next()  //Change to next texture (picture mode)
+{       //This function is used twice - by the menu and timer. Therefor, it is a dedicated function.
+    current_texture++;
+    integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
+    if(check == 0)
+    {
+        llSetTexture(BLANK,DISPLAY_ON_SIDE);
+        current_texture = 0;
+        report("No pictures found.");
+        return;
+    }
+    if(check == current_texture)
+        current_texture = 0;
+    
+    display_texture(check);
+    return;
+}
+
+//////////////
+// from hufflets...
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        llListen(EXTERNAL_TOUCH_CHANNEL, "", NULL_KEY, "");
+            // we listen on our touch channel in all cases and in all states.  this allows us
+            // to always pass along the user's touch from other prims to run the menus.
+        chan = (integer)llFrand(1000) + 1000;   //Pick a random listen channel for the listener
+        if(PICTURE_ROTATION_TIMER <= 0)         //Ensure the value is no less or equal 0
+            PICTURE_ROTATION_TIMER = 1;
+        llListenRemove(listenHandle);
+        listenHandle = -1;
+        last_owner = llGetOwner();
+        groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME);
+        off();
+        llOpenRemoteDataChannel();
+        // fred's changes to start up in picture viewing looper.
+        mode = 1;  // picture viewing.
+        pictures();  // show the pictures.
+        loop_image = TRUE;
+        llSetTimerEvent(PICTURE_ROTATION_TIMER);  // keep showing new pics.
+    }
+    
+    on_rez(integer i)
+    {
+        llSay(0,"Welcome to FreeView - your free, open-source television!");
+        llResetScript();
+    }
+
+    touch_start(integer total_number)
+    {
+        //-------------------------------------------------------------------------------
+        //Listen only to owner or group member. Edit this code to change access controls.
+        if(llDetectedKey(0) != llGetOwner() && llDetectedGroup(0) == FALSE)
+            return;
+        //-------------------------------------------------------------------------------
+
+        menu(llDetectedKey(0));
+    }
+    
+    changed(integer change)
+    {
+        if(change == CHANGED_INVENTORY) //If inventory change
+        {
+            if(mode == 1)   //If picture mode
+            {
+                integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
+                if(check != 0)
+                {
+                    current_texture = 0;
+                    display_texture(check);
+                }
+                else
+                {
+                    llSetTexture(BLANK,DISPLAY_ON_SIDE);
+                    report("No pictures found.");
+                }
+            }
+            else
+                if(mode == 2)   //If video mode
+                    if(finditem(NOTECARD) != -1)    //And bookmarks notecard present
+                        if(notecardkey != llGetInventoryKey(NOTECARD))
+                            tempuser = llGetNumberOfNotecardLines(NOTECARD);    //Reload number of lines
+        }
+        else if(change == CHANGED_OWNER)
+        {
+            isGroup = TRUE;
+            last_owner = llGetOwner();
+            groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME);
+            
+            if(mode == 2)
+            {
+                llSay(0,"Detected change in ownership. Attempting to obtain current parcel media texture...");
+                video();
+            }
+        }
+    }
+    
+    listen(integer channel, string name, key id, string message)
+    {
+        if ( (channel == EXTERNAL_TOUCH_CHANNEL) && is_prefix(message, "touched")) {
+            // pretend we got touched by the av.
+            message = llDeleteSubString(message, 0, 6);
+            menu((key)message);
+            return;
+        }        
+        if(message == "Pictures")
+        {
+            if(mode == 2)
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
+            pictures();
+            mode = 1;
+            menu(id);
+            return;
+        }
+        if(message == "Video")
+        {
+            video();
+            mode = 2;
+            menu(id);
+            return;
+        }
+        if(message == "Power off")
+        {
+            if(mode == 2)
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
+            off();
+            mode = 0;
+            return;
+        }
+        if(message == "Help")
+        {
+            llSay(0,"Help documentation is available at: http://www.slguide.com/help");
+            if(isGroup)
+            {
+                if(id == NULL_KEY)
+                {
+                    llSay(0,"FreeView cannot load help pages while set to group without the remote.");
+                    llSay(0,"For further assistance, please consult: http://slguide.com/help");
+                }
+                else
+                    tell_remote("HELP"+(string)id+(string)XML_channel);
+            }
+            else
+                llLoadURL(id,"Help pages for FreeView","http://www.slguide.com?c="+(string)XML_channel+"&help=1");
+        }
+        if(mode == 1)
+        {
+            if(message == "Browse")
+            {
+                loop_image = FALSE;
+                browse(id);
+                return;
+            }
+            if(message == "Next")
+            {
+                extendtimer();
+                next();
+                browse(id);
+            }
+            if(message == "Back")
+            {
+                extendtimer();
+                current_texture--;
+                integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
+                if(check == 0)
+                {
+                    llSetTexture(BLANK,DISPLAY_ON_SIDE);
+                    current_texture = 0;
+                    report("No pictures found.");
+                    return;
+                }
+                if(current_texture < 0)
+                    current_texture = check - 1;
+                
+                display_texture(check);
+                
+                browse(id);
+                return;
+            }
+            if(message == "Menu")
+            {
+                menu(id);
+                return;
+            }
+            if(message == "Loop")
+            {
+                llSetTimerEvent(PICTURE_ROTATION_TIMER);
+                loop_image = TRUE;
+                llOwnerSay("Picture will change every "+(string)PICTURE_ROTATION_TIMER+" seconds.");
+                return;
+            }
+            if(message == "Unloop")
+            {
+                loop_image = FALSE;
+                llOwnerSay("Picture loop disabled.");
+                return;
+            }
+            if(message == "Fix scale")
+            {
+                llSay(0,"Setting display texture to 1,1 repeats and 0,0 offset.");
+                llScaleTexture(1, 1, DISPLAY_ON_SIDE);
+                llOffsetTexture(0, 0, DISPLAY_ON_SIDE);
+                return;
+            }
+        }
+        if(mode == 2)
+        {
+            if(channel == REMOTE_CHANNEL)
+            {
+                if(encryption == 0)
+                    encryption = (integer)message;
+                llListenRemove(listenRemote);
+                listenRemote = -1;
+                llSay(0,"Remote configured ("+(string)id+")");
+            }
+                
+            if(message == "TV Guide")
+            {
+                if(isGroup)
+                {
+                    if(!encryption)
+                    {
+                        llSay(0,"** Error - This FreeView object has been deeded to group. You must use a Remote control to open the TV Guide.");
+                        llSay(0,"You can set up the remote control from the Video -> Configuration menu. Please refer to the notecard for further assistance.");
+                        return;
+                    }
+                    tell_remote((string)id+(string)XML_channel+(string)llGetOwner());
+                }
+                else
+                    llLoadURL(id, "Come to the Guide to Start Your Viewer Playing!", "http://slguide.com/index.php?v=" + (string)llGetKey() + "&c=" + (string)XML_channel + "&o=" + (string)llGetOwner() + "&");
+                return;
+            }
+
+            string header = "Video mode"+moviename+": ";
+            
+            if(message == "<< Prev")
+            {
+                notecardline--;
+                if(notecardline < 0)
+                    notecardline = numberofnotecardlines - 1;
+                tempuser = id;
+                llGetNotecardLine(NOTECARD,notecardline);
+                return;
+            }
+            if(message == "Next >>")
+            {
+                notecardline++;
+                if(notecardline >= numberofnotecardlines)
+                    notecardline = 0;
+                tempuser = id;
+                llGetNotecardLine(NOTECARD,notecardline);
+                return;
+            }
+            if(message == "Use")
+            {
+                if(tempurl == "** No URL specified! **")
+                    tempurl = "";
+                seturl(tempurl,id);
+                return;
+            }
+                    
+            if(message == "Menu")
+            {
+                menu(id);
+                return;
+            }
+            if(message == "Configure")
+            {
+                config(id);
+                return;
+            }
+            if(message == "Bookmarks")
+            {
+                if(notecardcheck != -1)
+                {
+                    llDialog(id,"Error: No valid bookmark data found in notecard '"+NOTECARD+"'.",["Menu"],chan);
+                    return;
+                }
+                if(finditem(NOTECARD) != -1)                
+                {
+                    tempuser = id;
+                    if(numberofnotecardlines < notecardline)
+                        notecardline = 0;
+                    llGetNotecardLine(NOTECARD,notecardline);
+                }
+                else
+                    llDialog(id,"Error: No notecard named "+NOTECARD+" found in contents.",["Menu"],chan);
+                return;
+            }
+            
+            if(llGetLandOwnerAt(llGetPos()) != llGetOwner())    //If we do not have permissions to actually do the following functions
+            {
+                llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner.");
+                menu(id);
+                return; //Abort
+            }
+            
+            if(listenUrl != -1 && channel == 1) //Incoming data from "Set URL" command (user spoke on channel 1)
+            {
+                llListenRemove(listenUrl);
+                listenUrl = -1;
+                tempmoviename = "";
+                seturl(message,id);
+            }
+            if(message == "Play")
+            {
+                report(header+"Playing");
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
+                return;
+            }
+            if(message == "Stop")
+            {
+                report(header+"Stopped");
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
+                return;
+            }
+            if(message == "Pause")
+            {
+                report(header+"Paused");
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PAUSE]);
+                return;
+            }
+            if(message == "Unload")
+            {
+                report(header+"Stopped");
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
+                return;
+            }
+            if(message == "Loop")
+            {
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_LOOP]);
+                return;
+            }
+            //URL , Auto-Scale, 
+            if(message == "Set URL")
+            {
+                report(header+"Stopped");
+                listenUrl = llListen(1,"",id,"");
+                llDialog(id,"Please type the URL of your choice with /1 in thebegining. For example, /1 www.google.com",["Ok"],938);
+                return;
+            }
+            if(message == "Align ON")
+            {
+                report(header+"Stopped");
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,TRUE]);
+                menu(id);
+                return;
+            }
+            if(message == "Align OFF")
+            {
+                report(header+"Stopped");
+                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,FALSE]);
+                menu(id);
+                return;
+            }
+            if(message == "Set Remote")
+            {
+                llSay(0,"Configuring remote...");
+                encryption = 0;
+                llListenRemove(listenRemote);
+                listenRemote = llListen(REMOTE_CHANNEL,"","","");
+                llSay(REMOTE_CHANNEL,"SETUP");
+            }
+        }
+    }
+    
+    dataserver(key queryid, string data)
+    {
+        if(queryid == groupcheck)       //Test if object is deeded to group
+        {
+            groupcheck = NULL_KEY;
+            isGroup = FALSE;
+            return;
+        }
+        
+        if(queryid == tempuser) //If just checking number of notecard lines
+        {
+            numberofnotecardlines = (integer)data;
+            notecardkey = llGetInventoryKey(NOTECARD);
+            notecardcheck = 0;
+            llGetNotecardLine(NOTECARD,notecardcheck);
+            return;
+        }
+        if(notecardcheck != -1)
+        {
+            if(data != EOF)
+            {
+                if(data == "")
+                {
+                    notecardcheck++;
+                    llGetNotecardLine(NOTECARD,notecardcheck);
+                }
+                else
+                {
+                    notecardcheck = -1;
+                    return;
+                }
+            }
+            else
+                return;
+        }
+
+        if(data == "" && notecardline < numberofnotecardlines)    //If user just pressed "enter" in bookmarks, skip
+        {
+            notecardline++;
+            llGetNotecardLine(NOTECARD,notecardline);
+            return;
+        }
+        
+        if(data == EOF)
+        {
+            notecardline = 0;
+            llGetNotecardLine(NOTECARD,notecardline);
+            return;
+        }
+        list parsed = llParseString2List(data,["|","| "," |"," | "],[]);    //Ensure no blank spaces before "http://".
+        string name = llList2String(parsed,0);
+        tempurl = llList2String(parsed,1);
+        if(tempurl == "")
+            tempurl = "** No URL specified! **";
+            
+        tempmoviename = name;
+                
+        llDialog(tempuser,"Bookmarks notecard ("+(string)(notecardline+1)+"/"+(string)numberofnotecardlines+")\n"+name+" ("+mediatype(llList2String(llParseString2List(tempurl,["."],[]),-1))+")\n"+tempurl,["<< Prev","Use","Next >>","Menu"],chan);
+    }
+    
+    remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval)
+    {
+        if (type == REMOTE_DATA_CHANNEL)
+        {
+            XML_channel = channel;
+        } 
+        else if(type == REMOTE_DATA_REQUEST)
+        {
+            list media_info = llParseString2List(sval, ["|"], []);
+            tempmoviename = llList2String(media_info,0);
+            seturl(llList2String(media_info,1),NULL_KEY);
+            llRemoteDataReply(channel, message_id, sval, 1);
+        }
+    }
+    
+    timer()
+    {
+        if(llGetTime() > listenTimer)       //If listener time expired...
+        {
+            llListenRemove(listenHandle);   //Remove listeneres.
+            llListenRemove(listenUrl);
+            llListenRemove(listenRemote);
+            listenHandle = -1;
+            listenUrl = -1;
+            listenRemote = -1;
+            listenTimer = -1;
+            if(loop_image == FALSE || mode != 1) //If we're not looping pictures or are in picture mode at all
+                llSetTimerEvent(0.0);   //Remove timer
+        }
+        
+        if(loop_image == TRUE && mode == 1) //If we're looping pictures and and we're in picture mode...
+            next(); //Next picture
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/FreeView_v1.8.txt b/huffware/huffotronic_updater_freebie_v5.3/FreeView_v1.8.txt
deleted file mode 100755 (executable)
index bb809fd..0000000
+++ /dev/null
@@ -1,834 +0,0 @@
-
-// huffware script: freeview modified by fred huffhines (see original license below).
-//
-// my changes are licensed this way:
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-// fred's changes include:
-// + assorted tweaks that i have since forgotten the details about.
-// + set the freeview to startup as a picture viewer, since that's my most common usage.
-
-//////////////
-// original author info and licensing:
-//FreeView 1.2 WebGuide (revision 4) - By CrystalShard Foo
-//Multifunctional Picture viewer and Video control script with webguide support
-//This script is distributed for free and must stay that way. 
-//      *** If you wish to give/sell a product using this script,  ***
-//      ***     THEN THE SCRIPT MUST REMAIN FULL-PERM AND FREE.    ***
-//      ***   Failure to do so will REVOKE your right to use it!   ***
-//Help for using this script can be obtained at: http://www.slguide.com/help
-//Feel free to modify this script and post your improvement. Leave the credits intact but feel free to add your name at its bottom.
-//Whats new:
-//- Now using FULL_BRIGHT instead of PRIM_MATERIAL_LIGHT for the screen display
-//- Added an ownership-change code to handle cases where FreeView gets deeded to group post Video Init.
-//- Renamed WebGuide to TV-Guide to reflect what this thing does better.
-//- Added a 'Fix Scale' button to Picture mode to help against user texture-scale changes.
-//- Additional minor help-tips and code improvements
-//Enjoy!
-//////////////
-
-
-//Constants
-integer PICTURE_ROTATION_TIMER = 30;   //In whole seconds
-
-integer DISPLAY_ON_SIDE = ALL_SIDES; //Change this to change where the image will be displayed
-
-key VIDEO_DEFAULT = "71b8ff26-087d-5f44-285b-d38df2e11a81";  //Test pattern - Used as default video texture when one is missing in parcel media
-key BLANK = "5748decc-f629-461c-9a36-a35a221fe21f"; //Blank texture - Used when there are no textures to display in Picture mode
-string NOTECARD = "bookmarks";  //Used to host URL bookmarks for video streams
-
-integer VIDEO_BRIGHT = TRUE;    //FULL_BRIGHT status for Video
-integer PICTURE_BRIGHT = TRUE;  //FULL_BRIGHT status for Picture
-
-integer REMOTE_CHANNEL = 9238742;
-
-integer EXTERNAL_TOUCH_CHANNEL = 1327;
-    // used by other prims to tell the viewer prim that the avatar has clicked on them.
-
-integer mode = 0;           //Freeview mode.
-                            //Mode 0 - Power off
-                            //Mode 1 - Picture viewer
-                            //Mode 2 - Video
-
-integer listenHandle = -1;      //Dialog menu listen handler
-integer listenUrl = -1;         //listen handler for channel 1 for when a URL is being added
-integer listenTimer = -1;       //Timer variable for removing all listeners after 2 minutes of listener inactivity
-integer listenRemote = -1;      //listen handler for the remote during initial setup
-integer encryption = 0;
-integer numberofnotecardlines = 0;  //Stores the current number of detected notecard lines.
-integer notecardline = 0;       //Current notecard line
-
-integer loop_image = FALSE;     //Are we looping pictures with a timer? (picture mode)
-integer current_texture = 0;    //Current texture number in inventory being displayed (picture mode)
-integer chan;                   //llDialog listen channel
-integer notecardcheck = 0;
-key video_texture;              //Currently used video display texture for parcel media stream
-
-string moviename;
-string tempmoviename;
-key notecardkey = NULL_KEY;
-key tempuser;                   //Temp key storge variable
-string tempurl;                 //Temp string storge variable
-
-integer isGroup = TRUE;
-key groupcheck = NULL_KEY;
-key last_owner;
-key XML_channel;
-
-pictures()      //Change mode to Picture Viewer
-{
-    //Initilize variables
-    
-    //Change prim to Light material while coloring face 0 black to prevent light-lag generation.
-    llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, PICTURE_BRIGHT]);
-
-    integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
-     
-    if(check == 0)
-    {
-        report("No pictures found.");
-        llSetTexture(BLANK,DISPLAY_ON_SIDE);
-        return;
-    }
-    else    
-        if(current_texture > check)
-            //Set to first texture if available
-            current_texture = 0;
-            
-    display_texture(current_texture);
-}
-
-video()         //Change mode to Video
-{
-    //Change prim to Light material while coloring face 0 black to prevent light-lag generation.
-    llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_NONE, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <1,1,1>, 1.0, PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, VIDEO_BRIGHT, PRIM_TEXTURE, DISPLAY_ON_SIDE, "62dc73ca-265f-7ca0-0453-e2a6aa60bb6f", llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]);
-    
-    report("Video mode"+moviename+": Stopped");
-    if(finditem(NOTECARD) != -1)
-        tempuser = llGetNumberOfNotecardLines(NOTECARD);
-    video_texture = llList2Key(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_TEXTURE]),0);
-    if(video_texture == NULL_KEY)
-    {
-        video_texture = VIDEO_DEFAULT;
-        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_TEXTURE,VIDEO_DEFAULT]);
-        llSay(0,"No parcel media texture found. Setting texture to default: "+(string)VIDEO_DEFAULT);
-        if(llGetLandOwnerAt(llGetPos()) != llGetOwner())
-            llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner.");
-    }
-    
-    llSetTexture(video_texture,DISPLAY_ON_SIDE);
-}
-
-off()
-{
-    report("Click to power on.");
-    llSetPrimitiveParams([PRIM_BUMP_SHINY, DISPLAY_ON_SIDE, PRIM_SHINY_LOW, PRIM_BUMP_NONE, PRIM_COLOR, DISPLAY_ON_SIDE, <0.1,0.1,0.1>, 1.0,PRIM_MATERIAL, PRIM_MATERIAL_PLASTIC, PRIM_FULLBRIGHT, DISPLAY_ON_SIDE, FALSE, PRIM_TEXTURE, DISPLAY_ON_SIDE, BLANK, llGetTextureScale(DISPLAY_ON_SIDE), llGetTextureOffset(DISPLAY_ON_SIDE), llGetTextureRot(DISPLAY_ON_SIDE)]);
-}
-
-integer finditem(string name)   //Finds and returns an item's inventory number
-{
-    integer i;
-    for(i=0;i<llGetInventoryNumber(INVENTORY_NOTECARD);i++)
-        if(llGetInventoryName(INVENTORY_NOTECARD,i) == NOTECARD)
-            return i;
-    return -1;
-}
-
-seturl(string url, key id)  //Set parcel media URL
-{
-    if(mode != 2)
-    {
-        video();
-        mode = 2;
-    }
-    moviename = tempmoviename;
-    if(moviename)
-        moviename = " ["+moviename+"]";
-    tempmoviename = "";
-    string oldurl = llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0);
-    if(oldurl != "")
-        llOwnerSay("Setting new media URL. The old URL was: "+oldurl);
-
-    llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,url]);
-    if(id!=NULL_KEY)
-        menu(id);
-    else
-    {
-        report("Video mode"+moviename+": Playing");
-        llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
-    }
-       
-    if(isGroup)
-        llSay(0,"New media URL set.");
-    else
-        llOwnerSay("New media URL set: "+url);
-}
-
-string mediatype(string ext)    //Returns a string stating the filetype of a file based on file extension
-{
-    ext = llToLower(ext);
-    if(ext == "swf")
-        return "Flash";
-    if(ext == "mov" || ext == "avi" || ext == "mpg" || ext == "mpeg" || ext == "smil")
-        return "Video";
-    if(ext == "jpg" || ext == "mpeg" || ext == "gif" || ext == "png" || ext == "pict" || ext == "tga" || ext == "tiff" || ext == "sgi" || ext == "bmp")
-        return "Image";
-    if(ext == "txt")
-        return "Text";
-    if(ext == "mp3" || ext == "wav")
-        return "Audio";
-    return "Unknown";
-}
-
-browse(key id)      //Image browser function for picture viewer mode
-{
-    integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
-    string header;
-    if(check > 0)
-        header = "("+(string)(current_texture+1)+"/"+(string)check+") "+llGetInventoryName(INVENTORY_TEXTURE,current_texture);
-    else
-        header = "No pictures found.";
-    llDialog(id,"** Monitor Control **\n Picture Viewer mode\n- Image browser\n- "+header,["Back","Next","Menu"],chan);
-    extendtimer();
-}
-
-report(string str)
-{
-    llSetObjectDesc(str);
-}
-
-extendtimer()       //Add another 2 minute to the Listen Removal timer (use when a Listen event is triggered)
-{
-    if(listenHandle == -1)
-        listenHandle = llListen(chan,"","","");
-    listenTimer = (integer)llGetTime() + 120;
-    if(loop_image == FALSE)
-        llSetTimerEvent(45);
-}
-
-config(key id)      //Configuration menu
-{
-    extendtimer();
-    llDialog(id,"Current media URL:\n"+llList2String(llParcelMediaQuery([PARCEL_MEDIA_COMMAND_URL]),0)+"\nTip: If the picture is abit off, try 'Align ON'",["Set URL","Align ON","Align OFF","Menu","Set Remote"],chan);
-}
-
-tell_remote(string str)
-{
-    llShout(REMOTE_CHANNEL,llXorBase64Strings(llStringToBase64((string)encryption + str), llStringToBase64((string)encryption)));
-}
-
-menu(key id)        //Dialog menus for all 3 modes
-{
-    list buttons = [];
-    string title = "** Monitor control **";
-    
-    extendtimer();
-
-    if(mode != 0)
-    {
-        if(mode == 1)       //Pictures menu
-        {
-            title+="\n  Picture Viewer mode";
-            buttons+=["Browse"];
-            if(loop_image == FALSE)
-                buttons+=["Loop"];
-            else
-                buttons+=["Unloop"];
-            buttons+=["Video","Power off","Help","Fix scale"];
-        }
-        else                //Video menu
-        {
-            title+="\n Video display mode\n"+moviename+"\nTip:\nClick 'TV Guide' to view the Online bookmarks.";
-            buttons+=["Pictures","Configure","Power off","Loop","Unload","Help","Play","Stop","Pause","TV Guide","Bookmarks","Set URL"];
-        }
-    }
-    else
-        buttons += ["Pictures","Video","Help"];
-    
-    llDialog(id,title,buttons,chan);
-}
-
-display_texture(integer check)  //Display texture and set name in description (picture mode)
-{                               //"Check" holds the number of textures in contents. The function uses "current_texture" to display.
-    string name = llGetInventoryName(INVENTORY_TEXTURE,current_texture);
-    llSetTexture(name,DISPLAY_ON_SIDE);
-    report("Showing picture: "+name+" ("+(string)(current_texture+1)+"/"+(string)check+")");
-}
-    
-
-next()  //Change to next texture (picture mode)
-{       //This function is used twice - by the menu and timer. Therefor, it is a dedicated function.
-    current_texture++;
-    integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
-    if(check == 0)
-    {
-        llSetTexture(BLANK,DISPLAY_ON_SIDE);
-        current_texture = 0;
-        report("No pictures found.");
-        return;
-    }
-    if(check == current_texture)
-        current_texture = 0;
-    
-    display_texture(check);
-    return;
-}
-
-//////////////
-// from hufflets...
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        llListen(EXTERNAL_TOUCH_CHANNEL, "", NULL_KEY, "");
-            // we listen on our touch channel in all cases and in all states.  this allows us
-            // to always pass along the user's touch from other prims to run the menus.
-        chan = (integer)llFrand(1000) + 1000;   //Pick a random listen channel for the listener
-        if(PICTURE_ROTATION_TIMER <= 0)         //Ensure the value is no less or equal 0
-            PICTURE_ROTATION_TIMER = 1;
-        llListenRemove(listenHandle);
-        listenHandle = -1;
-        last_owner = llGetOwner();
-        groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME);
-        off();
-        llOpenRemoteDataChannel();
-        // fred's changes to start up in picture viewing looper.
-        mode = 1;  // picture viewing.
-        pictures();  // show the pictures.
-        loop_image = TRUE;
-        llSetTimerEvent(PICTURE_ROTATION_TIMER);  // keep showing new pics.
-    }
-    
-    on_rez(integer i)
-    {
-        llSay(0,"Welcome to FreeView - your free, open-source television!");
-        llResetScript();
-    }
-
-    touch_start(integer total_number)
-    {
-        //-------------------------------------------------------------------------------
-        //Listen only to owner or group member. Edit this code to change access controls.
-        if(llDetectedKey(0) != llGetOwner() && llDetectedGroup(0) == FALSE)
-            return;
-        //-------------------------------------------------------------------------------
-
-        menu(llDetectedKey(0));
-    }
-    
-    changed(integer change)
-    {
-        if(change == CHANGED_INVENTORY) //If inventory change
-        {
-            if(mode == 1)   //If picture mode
-            {
-                integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
-                if(check != 0)
-                {
-                    current_texture = 0;
-                    display_texture(check);
-                }
-                else
-                {
-                    llSetTexture(BLANK,DISPLAY_ON_SIDE);
-                    report("No pictures found.");
-                }
-            }
-            else
-                if(mode == 2)   //If video mode
-                    if(finditem(NOTECARD) != -1)    //And bookmarks notecard present
-                        if(notecardkey != llGetInventoryKey(NOTECARD))
-                            tempuser = llGetNumberOfNotecardLines(NOTECARD);    //Reload number of lines
-        }
-        else if(change == CHANGED_OWNER)
-        {
-            isGroup = TRUE;
-            last_owner = llGetOwner();
-            groupcheck = llRequestAgentData(llGetOwner(),DATA_NAME);
-            
-            if(mode == 2)
-            {
-                llSay(0,"Detected change in ownership. Attempting to obtain current parcel media texture...");
-                video();
-            }
-        }
-    }
-    
-    listen(integer channel, string name, key id, string message)
-    {
-        if ( (channel == EXTERNAL_TOUCH_CHANNEL) && is_prefix(message, "touched")) {
-            // pretend we got touched by the av.
-            message = llDeleteSubString(message, 0, 6);
-            menu((key)message);
-            return;
-        }        
-        if(message == "Pictures")
-        {
-            if(mode == 2)
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
-            pictures();
-            mode = 1;
-            menu(id);
-            return;
-        }
-        if(message == "Video")
-        {
-            video();
-            mode = 2;
-            menu(id);
-            return;
-        }
-        if(message == "Power off")
-        {
-            if(mode == 2)
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
-            off();
-            mode = 0;
-            return;
-        }
-        if(message == "Help")
-        {
-            llSay(0,"Help documentation is available at: http://www.slguide.com/help");
-            if(isGroup)
-            {
-                if(id == NULL_KEY)
-                {
-                    llSay(0,"FreeView cannot load help pages while set to group without the remote.");
-                    llSay(0,"For further assistance, please consult: http://slguide.com/help");
-                }
-                else
-                    tell_remote("HELP"+(string)id+(string)XML_channel);
-            }
-            else
-                llLoadURL(id,"Help pages for FreeView","http://www.slguide.com?c="+(string)XML_channel+"&help=1");
-        }
-        if(mode == 1)
-        {
-            if(message == "Browse")
-            {
-                loop_image = FALSE;
-                browse(id);
-                return;
-            }
-            if(message == "Next")
-            {
-                extendtimer();
-                next();
-                browse(id);
-            }
-            if(message == "Back")
-            {
-                extendtimer();
-                current_texture--;
-                integer check = llGetInventoryNumber(INVENTORY_TEXTURE);
-                if(check == 0)
-                {
-                    llSetTexture(BLANK,DISPLAY_ON_SIDE);
-                    current_texture = 0;
-                    report("No pictures found.");
-                    return;
-                }
-                if(current_texture < 0)
-                    current_texture = check - 1;
-                
-                display_texture(check);
-                
-                browse(id);
-                return;
-            }
-            if(message == "Menu")
-            {
-                menu(id);
-                return;
-            }
-            if(message == "Loop")
-            {
-                llSetTimerEvent(PICTURE_ROTATION_TIMER);
-                loop_image = TRUE;
-                llOwnerSay("Picture will change every "+(string)PICTURE_ROTATION_TIMER+" seconds.");
-                return;
-            }
-            if(message == "Unloop")
-            {
-                loop_image = FALSE;
-                llOwnerSay("Picture loop disabled.");
-                return;
-            }
-            if(message == "Fix scale")
-            {
-                llSay(0,"Setting display texture to 1,1 repeats and 0,0 offset.");
-                llScaleTexture(1, 1, DISPLAY_ON_SIDE);
-                llOffsetTexture(0, 0, DISPLAY_ON_SIDE);
-                return;
-            }
-        }
-        if(mode == 2)
-        {
-            if(channel == REMOTE_CHANNEL)
-            {
-                if(encryption == 0)
-                    encryption = (integer)message;
-                llListenRemove(listenRemote);
-                listenRemote = -1;
-                llSay(0,"Remote configured ("+(string)id+")");
-            }
-                
-            if(message == "TV Guide")
-            {
-                if(isGroup)
-                {
-                    if(!encryption)
-                    {
-                        llSay(0,"** Error - This FreeView object has been deeded to group. You must use a Remote control to open the TV Guide.");
-                        llSay(0,"You can set up the remote control from the Video -> Configuration menu. Please refer to the notecard for further assistance.");
-                        return;
-                    }
-                    tell_remote((string)id+(string)XML_channel+(string)llGetOwner());
-                }
-                else
-                    llLoadURL(id, "Come to the Guide to Start Your Viewer Playing!", "http://slguide.com/index.php?v=" + (string)llGetKey() + "&c=" + (string)XML_channel + "&o=" + (string)llGetOwner() + "&");
-                return;
-            }
-
-            string header = "Video mode"+moviename+": ";
-            
-            if(message == "<< Prev")
-            {
-                notecardline--;
-                if(notecardline < 0)
-                    notecardline = numberofnotecardlines - 1;
-                tempuser = id;
-                llGetNotecardLine(NOTECARD,notecardline);
-                return;
-            }
-            if(message == "Next >>")
-            {
-                notecardline++;
-                if(notecardline >= numberofnotecardlines)
-                    notecardline = 0;
-                tempuser = id;
-                llGetNotecardLine(NOTECARD,notecardline);
-                return;
-            }
-            if(message == "Use")
-            {
-                if(tempurl == "** No URL specified! **")
-                    tempurl = "";
-                seturl(tempurl,id);
-                return;
-            }
-                    
-            if(message == "Menu")
-            {
-                menu(id);
-                return;
-            }
-            if(message == "Configure")
-            {
-                config(id);
-                return;
-            }
-            if(message == "Bookmarks")
-            {
-                if(notecardcheck != -1)
-                {
-                    llDialog(id,"Error: No valid bookmark data found in notecard '"+NOTECARD+"'.",["Menu"],chan);
-                    return;
-                }
-                if(finditem(NOTECARD) != -1)                
-                {
-                    tempuser = id;
-                    if(numberofnotecardlines < notecardline)
-                        notecardline = 0;
-                    llGetNotecardLine(NOTECARD,notecardline);
-                }
-                else
-                    llDialog(id,"Error: No notecard named "+NOTECARD+" found in contents.",["Menu"],chan);
-                return;
-            }
-            
-            if(llGetLandOwnerAt(llGetPos()) != llGetOwner())    //If we do not have permissions to actually do the following functions
-            {
-                llSay(0,"Error: Cannot modify parcel media settings. "+llGetObjectName()+" is not owned by parcel owner.");
-                menu(id);
-                return; //Abort
-            }
-            
-            if(listenUrl != -1 && channel == 1) //Incoming data from "Set URL" command (user spoke on channel 1)
-            {
-                llListenRemove(listenUrl);
-                listenUrl = -1;
-                tempmoviename = "";
-                seturl(message,id);
-            }
-            if(message == "Play")
-            {
-                report(header+"Playing");
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
-                return;
-            }
-            if(message == "Stop")
-            {
-                report(header+"Stopped");
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_STOP]);
-                return;
-            }
-            if(message == "Pause")
-            {
-                report(header+"Paused");
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PAUSE]);
-                return;
-            }
-            if(message == "Unload")
-            {
-                report(header+"Stopped");
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_UNLOAD]);
-                return;
-            }
-            if(message == "Loop")
-            {
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_LOOP]);
-                return;
-            }
-            //URL , Auto-Scale, 
-            if(message == "Set URL")
-            {
-                report(header+"Stopped");
-                listenUrl = llListen(1,"",id,"");
-                llDialog(id,"Please type the URL of your choice with /1 in thebegining. For example, /1 www.google.com",["Ok"],938);
-                return;
-            }
-            if(message == "Align ON")
-            {
-                report(header+"Stopped");
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,TRUE]);
-                menu(id);
-                return;
-            }
-            if(message == "Align OFF")
-            {
-                report(header+"Stopped");
-                llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,FALSE]);
-                menu(id);
-                return;
-            }
-            if(message == "Set Remote")
-            {
-                llSay(0,"Configuring remote...");
-                encryption = 0;
-                llListenRemove(listenRemote);
-                listenRemote = llListen(REMOTE_CHANNEL,"","","");
-                llSay(REMOTE_CHANNEL,"SETUP");
-            }
-        }
-    }
-    
-    dataserver(key queryid, string data)
-    {
-        if(queryid == groupcheck)       //Test if object is deeded to group
-        {
-            groupcheck = NULL_KEY;
-            isGroup = FALSE;
-            return;
-        }
-        
-        if(queryid == tempuser) //If just checking number of notecard lines
-        {
-            numberofnotecardlines = (integer)data;
-            notecardkey = llGetInventoryKey(NOTECARD);
-            notecardcheck = 0;
-            llGetNotecardLine(NOTECARD,notecardcheck);
-            return;
-        }
-        if(notecardcheck != -1)
-        {
-            if(data != EOF)
-            {
-                if(data == "")
-                {
-                    notecardcheck++;
-                    llGetNotecardLine(NOTECARD,notecardcheck);
-                }
-                else
-                {
-                    notecardcheck = -1;
-                    return;
-                }
-            }
-            else
-                return;
-        }
-
-        if(data == "" && notecardline < numberofnotecardlines)    //If user just pressed "enter" in bookmarks, skip
-        {
-            notecardline++;
-            llGetNotecardLine(NOTECARD,notecardline);
-            return;
-        }
-        
-        if(data == EOF)
-        {
-            notecardline = 0;
-            llGetNotecardLine(NOTECARD,notecardline);
-            return;
-        }
-        list parsed = llParseString2List(data,["|","| "," |"," | "],[]);    //Ensure no blank spaces before "http://".
-        string name = llList2String(parsed,0);
-        tempurl = llList2String(parsed,1);
-        if(tempurl == "")
-            tempurl = "** No URL specified! **";
-            
-        tempmoviename = name;
-                
-        llDialog(tempuser,"Bookmarks notecard ("+(string)(notecardline+1)+"/"+(string)numberofnotecardlines+")\n"+name+" ("+mediatype(llList2String(llParseString2List(tempurl,["."],[]),-1))+")\n"+tempurl,["<< Prev","Use","Next >>","Menu"],chan);
-    }
-    
-    remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval)
-    {
-        if (type == REMOTE_DATA_CHANNEL)
-        {
-            XML_channel = channel;
-        } 
-        else if(type == REMOTE_DATA_REQUEST)
-        {
-            list media_info = llParseString2List(sval, ["|"], []);
-            tempmoviename = llList2String(media_info,0);
-            seturl(llList2String(media_info,1),NULL_KEY);
-            llRemoteDataReply(channel, message_id, sval, 1);
-        }
-    }
-    
-    timer()
-    {
-        if(llGetTime() > listenTimer)       //If listener time expired...
-        {
-            llListenRemove(listenHandle);   //Remove listeneres.
-            llListenRemove(listenUrl);
-            llListenRemove(listenRemote);
-            listenHandle = -1;
-            listenUrl = -1;
-            listenRemote = -1;
-            listenTimer = -1;
-            if(loop_image == FALSE || mode != 1) //If we're not looping pictures or are in picture mode at all
-                llSetTimerEvent(0.0);   //Remove timer
-        }
-        
-        if(loop_image == TRUE && mode == 1) //If we're looping pictures and and we're in picture mode...
-            next(); //Next picture
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/JukeBox_v1.6.lsl b/huffware/huffotronic_updater_freebie_v5.3/JukeBox_v1.6.lsl
new file mode 100755 (executable)
index 0000000..21b4842
--- /dev/null
@@ -0,0 +1,367 @@
+
+// jukebox script.  unknown provenance.
+// modified for use in opensim by fred huffhines.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+float INTERVAL = 9.00;
+
+integer IS_OPENSIM = TRUE;
+    // this must be set to true to turn off the sound queuing.  opensim does not currently implement it.
+
+float SOUND_OFFSET_PERIOD = 1.1;  // number of seconds to start the sound in advance.
+
+integer LISTEN_CHAN = 2000;
+integer SEND_CHAN = 2001;
+float VOLUME = 1.0;
+
+integer g_iSound;
+integer total_tracks;
+integer g_iListenCtrl = -1;
+integer g_iPlaying;
+integer g_iLinked;
+integer g_iStop;
+integer g_iPod;
+string g_sLink;
+
+// DEBUG
+integer g_iWasLinked;
+integer g_iFinished;
+
+list song_names;
+    // hold onto the names of all the songs so we don't need to keep
+    // going back to inventory.
+
+Initialize()
+{
+    llSetText(llGetObjectName(), <0, 100, 100>, 10);
+    
+    // reset listeners
+    if ( g_iListenCtrl != -1 )
+    {
+        llListenRemove(g_iListenCtrl);
+    }
+    g_iListenCtrl = llListen(LISTEN_CHAN,"","","");
+    g_iPlaying = 0;
+    g_iLinked = 0;
+
+    integer i;
+    total_tracks = llGetInventoryNumber(INVENTORY_SOUND);
+    for ( i = 0; i < total_tracks; i++ ) {
+        string name = llGetInventoryName(INVENTORY_SOUND, i);
+        song_names += [ name ];
+        llPreloadSound(name);
+    }
+//llOwnerSay("got song names list: " + (string)song_names);
+}
+
+
+
+PlaySong()
+{
+    integer i;
+
+    g_iPlaying = 1;    
+    llWhisper(0, "Playing...");
+    if (!IS_OPENSIM) {
+        llSetSoundQueueing(TRUE);
+    }
+    llAdjustSoundVolume(1.0);
+    llPlaySound(llList2String(song_names, 0), VOLUME);
+    llPreloadSound(llList2String(song_names, 1));
+    // set the timer interval for just before the track chunk ends.
+    llSetTimerEvent(INTERVAL - SOUND_OFFSET_PERIOD);
+    g_iSound = 1;
+}
+
+
+StopSong()
+{
+    g_iPlaying = 0;
+    llWhisper(0, "Stopping...");
+    llStopSound();
+    llAdjustSoundVolume(0);
+    llSetTimerEvent(0.0);
+}
+
+
+integer CheckLink()
+{
+    string sLink;
+    
+    sLink = llGetLinkName(1);
+    g_sLink = sLink;
+    if ( llGetSubString(sLink,0,6) == "Jukebox" )
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        Initialize();
+    }
+    
+    on_rez(integer start_param)
+    {
+        Initialize();
+        if ( start_param )
+        {
+            g_iPod = start_param - 1;
+            if ( g_iPod )
+            {
+                llRequestPermissions(llGetOwner(),PERMISSION_ATTACH);
+            } else {
+                // Tell the controller what the CD key is so it can link
+                llWhisper(SEND_CHAN,"LINK " + (string)llGetKey());
+            }
+        }
+    }
+    
+    changed(integer change)
+    {
+        if ( change == CHANGED_LINK )
+        {
+            if ( llGetLinkNumber() == 0 )
+            {
+                StopSong();
+                llDie();
+            } else {
+                if ( g_iStop )
+                {
+                    llMessageLinked(1,llGetLinkNumber(),"UNLINK","");
+                } else {
+                    llMessageLinked(1,llGetLinkNumber(),"LINKID","");
+                    g_iWasLinked = 1;
+                }
+            }
+        }
+    }
+    
+    attach(key id)
+    {
+        if ( id == NULL_KEY )
+        {
+            llDie();
+        } else {
+            PlaySong();
+        }
+    }
+    
+    run_time_permissions(integer perm)
+    {
+        if ( perm == PERMISSION_ATTACH )
+        {
+            llAttachToAvatar(ATTACH_LSHOULDER);
+            llSetTexture("clear",ALL_SIDES);
+        }
+    }
+    
+    touch_start(integer total_number)
+    {
+        integer i;
+        
+        for ( i = 0; i < total_number; i++ )
+        {
+            if ( llDetectedKey(i) == llGetOwner() )
+            {
+//llWhisper(0,"DEBUG: g_iPlaying=" + (string)g_iPlaying);
+//llWhisper(0,"DEBUG: Link=" + (string)llGetLinkNumber());
+//llWhisper(0,"DEBUG: g_iWasLinked=" + (string)g_iWasLinked);
+//llWhisper(0,"DEBUG: g_iFinished=" + (string)g_iFinished);
+                if ( g_iPlaying ) StopSong();
+                else PlaySong();
+            }
+        }
+    }
+    
+    listen(integer channel, string name, key id, string message)
+    {
+        if ( message == "RESET" )
+        {
+            if ( llGetLinkNumber() == 0 )
+            {
+                llDie();
+            } else {
+                llMessageLinked(1,llGetLinkNumber(),"UNLINK","");
+            }
+        }
+        
+        if ( message == "STOP" )
+        {
+            if ( g_iPod )
+            {
+                StopSong();
+                llDetachFromAvatar();
+            }
+        }
+    }
+
+    link_message(integer sender_num, integer num, string str, key id)
+    {
+        if ( str == "PLAY" )
+        {
+            if ( !g_iPlaying )
+            {
+                PlaySong();
+            }
+            return;
+        }
+        
+        if ( str == "STOP" )
+        {
+            g_iStop = 1;
+            StopSong();
+            llMessageLinked(1,llGetLinkNumber(),"UNLINK","");
+        }
+        
+        if ( str == "VOLUME" )
+        {
+            VOLUME = (float)num / 10.0;
+            llAdjustSoundVolume(VOLUME);
+        }
+    }
+    
+    timer()
+    {
+        if ( g_iPlaying )
+        {
+//llWhisper(0, "playing song #" + (string)(g_iSound+1) + ": " +  llList2String(song_names, g_iSound));
+            llPlaySound(llList2String(song_names, g_iSound),VOLUME);
+            if ( g_iSound < (total_tracks - 1) )
+            {
+                llPreloadSound(llList2String(song_names, g_iSound + 1));
+            }
+            g_iSound++;
+            if ( g_iSound >= total_tracks )
+            {
+                llSetTimerEvent(INTERVAL + 5.0);
+                g_iPlaying = 0;
+            } else {
+                llSetTimerEvent(INTERVAL - SOUND_OFFSET_PERIOD);
+            }                
+        } else {
+            if ( llGetLinkNumber() != 0 )
+            {
+                llSetTimerEvent(0.0);
+                if ( g_iPod )
+                {
+                    llWhisper(SEND_CHAN,"FINISH");
+                    llDetachFromAvatar();
+                } else {
+                    llMessageLinked(1,0,"FINISH","");
+                    g_iFinished = 1;
+                }
+            }
+        }
+    }
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/JukeBox_v1.6.txt b/huffware/huffotronic_updater_freebie_v5.3/JukeBox_v1.6.txt
deleted file mode 100755 (executable)
index 21b4842..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-
-// jukebox script.  unknown provenance.
-// modified for use in opensim by fred huffhines.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-float INTERVAL = 9.00;
-
-integer IS_OPENSIM = TRUE;
-    // this must be set to true to turn off the sound queuing.  opensim does not currently implement it.
-
-float SOUND_OFFSET_PERIOD = 1.1;  // number of seconds to start the sound in advance.
-
-integer LISTEN_CHAN = 2000;
-integer SEND_CHAN = 2001;
-float VOLUME = 1.0;
-
-integer g_iSound;
-integer total_tracks;
-integer g_iListenCtrl = -1;
-integer g_iPlaying;
-integer g_iLinked;
-integer g_iStop;
-integer g_iPod;
-string g_sLink;
-
-// DEBUG
-integer g_iWasLinked;
-integer g_iFinished;
-
-list song_names;
-    // hold onto the names of all the songs so we don't need to keep
-    // going back to inventory.
-
-Initialize()
-{
-    llSetText(llGetObjectName(), <0, 100, 100>, 10);
-    
-    // reset listeners
-    if ( g_iListenCtrl != -1 )
-    {
-        llListenRemove(g_iListenCtrl);
-    }
-    g_iListenCtrl = llListen(LISTEN_CHAN,"","","");
-    g_iPlaying = 0;
-    g_iLinked = 0;
-
-    integer i;
-    total_tracks = llGetInventoryNumber(INVENTORY_SOUND);
-    for ( i = 0; i < total_tracks; i++ ) {
-        string name = llGetInventoryName(INVENTORY_SOUND, i);
-        song_names += [ name ];
-        llPreloadSound(name);
-    }
-//llOwnerSay("got song names list: " + (string)song_names);
-}
-
-
-
-PlaySong()
-{
-    integer i;
-
-    g_iPlaying = 1;    
-    llWhisper(0, "Playing...");
-    if (!IS_OPENSIM) {
-        llSetSoundQueueing(TRUE);
-    }
-    llAdjustSoundVolume(1.0);
-    llPlaySound(llList2String(song_names, 0), VOLUME);
-    llPreloadSound(llList2String(song_names, 1));
-    // set the timer interval for just before the track chunk ends.
-    llSetTimerEvent(INTERVAL - SOUND_OFFSET_PERIOD);
-    g_iSound = 1;
-}
-
-
-StopSong()
-{
-    g_iPlaying = 0;
-    llWhisper(0, "Stopping...");
-    llStopSound();
-    llAdjustSoundVolume(0);
-    llSetTimerEvent(0.0);
-}
-
-
-integer CheckLink()
-{
-    string sLink;
-    
-    sLink = llGetLinkName(1);
-    g_sLink = sLink;
-    if ( llGetSubString(sLink,0,6) == "Jukebox" )
-    {
-        return TRUE;
-    }
-    return FALSE;
-}
-
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        Initialize();
-    }
-    
-    on_rez(integer start_param)
-    {
-        Initialize();
-        if ( start_param )
-        {
-            g_iPod = start_param - 1;
-            if ( g_iPod )
-            {
-                llRequestPermissions(llGetOwner(),PERMISSION_ATTACH);
-            } else {
-                // Tell the controller what the CD key is so it can link
-                llWhisper(SEND_CHAN,"LINK " + (string)llGetKey());
-            }
-        }
-    }
-    
-    changed(integer change)
-    {
-        if ( change == CHANGED_LINK )
-        {
-            if ( llGetLinkNumber() == 0 )
-            {
-                StopSong();
-                llDie();
-            } else {
-                if ( g_iStop )
-                {
-                    llMessageLinked(1,llGetLinkNumber(),"UNLINK","");
-                } else {
-                    llMessageLinked(1,llGetLinkNumber(),"LINKID","");
-                    g_iWasLinked = 1;
-                }
-            }
-        }
-    }
-    
-    attach(key id)
-    {
-        if ( id == NULL_KEY )
-        {
-            llDie();
-        } else {
-            PlaySong();
-        }
-    }
-    
-    run_time_permissions(integer perm)
-    {
-        if ( perm == PERMISSION_ATTACH )
-        {
-            llAttachToAvatar(ATTACH_LSHOULDER);
-            llSetTexture("clear",ALL_SIDES);
-        }
-    }
-    
-    touch_start(integer total_number)
-    {
-        integer i;
-        
-        for ( i = 0; i < total_number; i++ )
-        {
-            if ( llDetectedKey(i) == llGetOwner() )
-            {
-//llWhisper(0,"DEBUG: g_iPlaying=" + (string)g_iPlaying);
-//llWhisper(0,"DEBUG: Link=" + (string)llGetLinkNumber());
-//llWhisper(0,"DEBUG: g_iWasLinked=" + (string)g_iWasLinked);
-//llWhisper(0,"DEBUG: g_iFinished=" + (string)g_iFinished);
-                if ( g_iPlaying ) StopSong();
-                else PlaySong();
-            }
-        }
-    }
-    
-    listen(integer channel, string name, key id, string message)
-    {
-        if ( message == "RESET" )
-        {
-            if ( llGetLinkNumber() == 0 )
-            {
-                llDie();
-            } else {
-                llMessageLinked(1,llGetLinkNumber(),"UNLINK","");
-            }
-        }
-        
-        if ( message == "STOP" )
-        {
-            if ( g_iPod )
-            {
-                StopSong();
-                llDetachFromAvatar();
-            }
-        }
-    }
-
-    link_message(integer sender_num, integer num, string str, key id)
-    {
-        if ( str == "PLAY" )
-        {
-            if ( !g_iPlaying )
-            {
-                PlaySong();
-            }
-            return;
-        }
-        
-        if ( str == "STOP" )
-        {
-            g_iStop = 1;
-            StopSong();
-            llMessageLinked(1,llGetLinkNumber(),"UNLINK","");
-        }
-        
-        if ( str == "VOLUME" )
-        {
-            VOLUME = (float)num / 10.0;
-            llAdjustSoundVolume(VOLUME);
-        }
-    }
-    
-    timer()
-    {
-        if ( g_iPlaying )
-        {
-//llWhisper(0, "playing song #" + (string)(g_iSound+1) + ": " +  llList2String(song_names, g_iSound));
-            llPlaySound(llList2String(song_names, g_iSound),VOLUME);
-            if ( g_iSound < (total_tracks - 1) )
-            {
-                llPreloadSound(llList2String(song_names, g_iSound + 1));
-            }
-            g_iSound++;
-            if ( g_iSound >= total_tracks )
-            {
-                llSetTimerEvent(INTERVAL + 5.0);
-                g_iPlaying = 0;
-            } else {
-                llSetTimerEvent(INTERVAL - SOUND_OFFSET_PERIOD);
-            }                
-        } else {
-            if ( llGetLinkNumber() != 0 )
-            {
-                llSetTimerEvent(0.0);
-                if ( g_iPod )
-                {
-                    llWhisper(SEND_CHAN,"FINISH");
-                    llDetachFromAvatar();
-                } else {
-                    llMessageLinked(1,0,"FINISH","");
-                    g_iFinished = 1;
-                }
-            }
-        }
-    }
-}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/TL_Door_fredmod_v4.4.lsl b/huffware/huffotronic_updater_freebie_v5.3/TL_Door_fredmod_v4.4.lsl
new file mode 100755 (executable)
index 0000000..0255c6c
--- /dev/null
@@ -0,0 +1,697 @@
+
+// fred huffhines mods:
+//
+// took away the universal skeleton key that was lodged in this script.
+//
+// stopped considering door's scale; this is not usually needed, plus we were blowing
+//      past the SL limit on object names.
+//
+// moved to only storing a couple digits after the decimal point; this is another
+//      crucial thing to limit the size of the object name.
+//
+// added a "toggle" command that behaves like touch, in that the door will be opened
+//      or closed based on current state.
+//
+// made the sensor distance required before the door will listen to someone into a
+//      configurable parameter, instead of the woefully tiny, hard-coded 5 meters.
+//
+// added debugging flag and switchable logging for debugging mode.
+//
+// *original license and author info below...*
+//
+// plus, timeless prototype said this about using the script in osgrid and elsewhere:
+//      "hi, thanks for asking, yes you may use the door script in other grids."
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+// more fred huffhines mods: (circa march 2012)
+//   added PASS_COMMANDS flag, which can be used to pass along any commands we
+// hear to anyone else on our same channel within the object.
+//   added stifling of commands heard so they don't get re-sent, causing endless
+// loops of door openings.
+
+
+//------------------------------------------------------
+// Timeless Linked Door Script by Timeless Prototype
+//------------------------------------------------------
+// The latest version of this script can always be found
+// in the Library section of the wiki:
+// http://www.secondlife.com/badgeo/
+// This script is free to use, but whereever it is used
+// the SCRIPT's permissions MUST be set to:
+// [x] Next owner can modify
+// [x] Next owner can copy
+// [x] Next owner can transfer
+// [x] Allow anyone to copy
+// [x] Share with group
+
+//------------------------------------------------------
+// USAGE INSTRUCTIONS FOR EVERYDAY USE:
+//------------------------------------------------------
+// Say the following commands on channel 0:
+// 'unlock'     - Unlocks all doors in range.
+// 'lock'       - Locks all doors in range and allows
+//                only the permitted users to open it.
+// To open the door, either Touch it, Walk into it or
+// say 'open' or say 'close'.
+
+//------------------------------------------------------
+// USAGE INSTRUCTIONS FOR BUILDERS:
+//------------------------------------------------------
+// 1. Copy and paste this script into the door prim and
+//    change the settings (see further down).
+// 2. The door prim must be linked to at least one other
+//    prim (could be linked to the house for example).
+// 3. The door prim MUST NOT be the root prim.
+// 4. Use Edit Linked Parts to move, rotate and size the
+//    door prim for the closed state.
+// 5. When ready, stand close to the door and say
+//    '/door closed' (this records the closed door
+//    position, rotation and size to the object's
+//    name and description).
+// 6. Use the Edit Linked parts to move, rotate and size
+//    the door prim for the opened state.
+// 7. When ready, stand close to the door and say
+//    '/door opened' (this records the opened door
+//    position, rotation and size).
+// 8. Once recorded it will not accept these commands
+//    again. If you do need to redo the settings then
+//    delete the Name and Description of the door prim
+//    (these are where the position information is
+//    stored), and then follow the steps above again.
+//    Note: deleting the object name won't save, so set
+//    the object name to 'Object' to reset the object
+//    name.
+
+//------------------------------------------------------
+// Change these settings to suit your needs.
+//------------------------------------------------------
+// To mute any/all of the sounds set the sound string(s)
+// to "" (empty string).
+// To get the UUID of a sound, right click on the sound
+// in your inventory and choose "Copy Asset UUID", then
+// paste the UUID in here.
+string      doorOpenSound       = "Door open";
+string      doorCloseSound      = "Door close";
+string      confirmedSound      = "69743cb2-e509-ed4d-4e52-e697dc13d7ac";
+string      accessDeniedSound   = "58da0f9f-42e5-8a8f-ee51-4fac6c247c98";
+string      doorBellSound       = ""; // Setting to empty stops door announcements too.
+float       autoCloseTime       = 120.0; // 0 seconds to disable auto close.
+integer     allowGroupToo       = TRUE; // Set to FALSE to disallow same group access to door.
+list        allowedAgentUUIDs   = []; // Comma-separated, quoted list of avatar UUIDs who are allowed access to this door.
+// was allowing this sneaky guy: "8efecbac-35de-4f40-89c1-2c772b83cafa"
+integer     listenChannel       = 10106;
+float       RESPONSE_DISTANCE   = 120.0;  // how far to allow a command from users with permission.
+integer     DEBUGGING           = FALSE;
+integer     PASS_COMMANDS       = TRUE;
+    // if true, then we will order other doors to open when we do.
+    // we use the listenChannel as the id to pass commands on, so that only the doors listening to
+    // the same place will hear our commands.
+integer     command_is_a_response  = FALSE;
+    // if this is true, then the door open and close must not re-echo their actions.
+
+//------------------------------------------------------
+// Leave the rest of the settings alone, these are
+// handled by the script itself.
+//------------------------------------------------------
+integer     isLocked            = FALSE; // Only when the door is locked do the permissions apply.
+integer     isOpen              = TRUE;
+vector      openPos             = ZERO_VECTOR;
+rotation    openRot             = ZERO_ROTATION;
+vector      closedPos           = ZERO_VECTOR;
+rotation    closedRot           = ZERO_ROTATION;
+key         openerKey           = NULL_KEY;
+key         closerKey           = NULL_KEY;
+integer     isSetup             = FALSE;
+integer     listenHandle        = 0;
+string      avatarName          = "";
+
+// zooms the sub-prim to a new rotation and position.
+jump_to_position(vector position, rotation new_rot)
+{
+    list config_blast = [ 
+        PRIM_SIZE, llGetScale(), ///????
+        // first jump away from where we started, trying to get past an opensim bug.
+//        PRIM_POSITION, ZERO_VECTOR,
+//        PRIM_POSITION, ZERO_VECTOR,
+//        PRIM_POSITION, ZERO_VECTOR,
+//        PRIM_POSITION, ZERO_VECTOR,
+//        PRIM_POSITION, ZERO_VECTOR,
+        PRIM_ROTATION, ZERO_ROTATION * new_rot / llGetRootRotation(),
+//        PRIM_POSITION, position,
+//        PRIM_POSITION, position,
+//        PRIM_POSITION, position,
+//        PRIM_POSITION, position,
+//        PRIM_POSITION, position,
+        PRIM_POSITION, position
+        ];
+    llSetLinkPrimitiveParams(llGetLinkNumber(), config_blast);
+if (DEBUGGING) llOwnerSay("want pos=" + (string)position + ", got=" + (string)llGetLocalPos()
++ ", and want rot=" + (string)new_rot + ", got=" + (string)llGetLocalRot());
+}
+
+mySayName(integer channel, string objectName, string message)
+{
+    string name = llGetObjectName();
+    llSetObjectName(objectName);
+    llSay(0, "/me " + message);
+    llSetObjectName(name);
+}
+
+mySay(integer channel, string message)
+{
+    string name = llGetObjectName();
+    llSetObjectName("Door");
+    llSay(0, message);
+    llSetObjectName(name);
+}
+
+myOwnerSay(string message)
+{
+    string name = llGetObjectName();
+    llSetObjectName("Door");
+    llOwnerSay(message);
+    llSetObjectName(name);
+}
+
+mySoundConfirmed()
+{
+    if (confirmedSound != "")
+    {
+        llTriggerSound(confirmedSound, 1.0);
+    }
+}
+
+mySoundAccessDenied()
+{
+    if (accessDeniedSound != "")
+    {
+        llTriggerSound(accessDeniedSound, 1.0);
+    }
+}
+
+myGetDoorParams()
+{
+    isSetup = FALSE;
+    if (llSubStringIndex(llGetObjectDesc(), "D;") == 0 && llSubStringIndex(llGetObjectName(), "D;") == 0)
+    {
+        list nameWords = llParseString2List(llGetObjectName(), [";"], []);
+        list descWords = llParseString2List(llGetObjectDesc(), [";"], []);
+        if (llGetListLength(nameWords) != 3 || llGetListLength(descWords) != 3)
+        {
+            myOwnerSay("The door prim's name and/or description has invalid syntax and/or number of parameters. Delete the door prim's name and description and setup the door prim again.");
+        }
+        else
+        {
+            openPos = (vector)llList2String(nameWords, 1);
+            openRot = (rotation)llList2String(nameWords, 2);
+            closedPos = (vector)llList2String(descWords, 1);
+            closedRot = (rotation)llList2String(descWords, 2);
+            isSetup = TRUE;
+        }
+//llSay(0, "got open pos=" + (string)(openPos) + " rot=" + (string)(openRot));
+//llSay(0, "got close pos=" + (string)(closedPos) + " rot=" + (string)(closedRot));
+        
+    }
+}
+
+// if open_state is true, the parms are for an open door.
+mySetDoorParams(integer open_state, vector Pos, rotation Rot)
+{
+    if (open_state) {
+        // parms for open state.
+        llSetObjectName("D;" + vector_chop(Pos) + ";" + rotation_chop(Rot));
+    } else {
+        // parms for closed state.
+        llSetObjectDesc("D;" + vector_chop(Pos) + ";" + rotation_chop(Rot));
+    }
+    isSetup = TRUE;
+}
+
+integer myPermissionCheck(key id)
+{
+    integer hasPermission = FALSE;
+    if (isLocked == FALSE) {
+        if (DEBUGGING) llOwnerSay("perm--unlocked: okay");
+        hasPermission = TRUE;
+    } else if (llGetOwnerKey(id) == llGetOwner()) {
+        if (DEBUGGING) llOwnerSay("perm--is owner: okay");
+        hasPermission = TRUE;
+    } else if (allowGroupToo == TRUE && llSameGroup(id)) {
+        if (DEBUGGING) llOwnerSay("perm--same group: okay");
+        hasPermission = TRUE;
+    } else if (llListFindList(allowedAgentUUIDs, [(string)id]) != -1) {
+        if (DEBUGGING) llOwnerSay("perm--in list: okay");
+        hasPermission = TRUE;
+    } else {
+        if (DEBUGGING) llOwnerSay("perm--not found anywhere: bad perms");
+    }
+    return hasPermission;
+}
+
+myOpenDoor()
+{
+    isOpen = FALSE;
+    myToggleDoor();
+}
+
+myCloseDoor()
+{
+    isOpen = TRUE;
+    myToggleDoor();
+}
+
+myToggleDoor()
+{
+    if (isSetup == FALSE)
+    {
+        myOwnerSay("The door prim has not been configured yet. Please read the usage instructions in the door script.");
+    }
+    else if (llGetLinkNumber() == 0 || llGetLinkNumber() == 1)
+    {
+        myOwnerSay("The door prim must be linked to at least one other prim and the door prim must not be the root prim");
+    }
+    else
+    {
+        isOpen = !isOpen;
+if (DEBUGGING) llOwnerSay("door open state is now=" + (string)isOpen);
+        if (isOpen)
+        {
+if (DEBUGGING) llOwnerSay("opening the door.");
+            if (doorBellSound != "")
+            {
+                llTriggerSound(doorBellSound, 1.0);
+                if (avatarName != "")
+                {
+                    mySayName(0, avatarName, "is at the door.");
+                    avatarName = "";
+                }
+            }
+            if (doorOpenSound != "")
+            {
+                llTriggerSound(doorOpenSound, 1.0);
+            }
+            jump_to_position(openPos, openRot);
+//            list config_blast = [ PRIM_POSITION, llGetLocalPos() + <4, 4, 4>,
+//                PRIM_ROTATION, ZERO_ROTATION * openRot / llGetRootRotation(),
+//                PRIM_POSITION, openPos
+////                PRIM_SIZE, llGetScale() 
+//                ];
+//            llSetPrimitiveParams(config_blast);
+//if (DEBUGGING) llOwnerSay("want pos=" + (string)openPos + ", got=" + (string)llGetLocalPos()
+//+ ", and want rot=" + (string)openRot + ", got=" + (string)llGetLocalRot());
+
+            if (PASS_COMMANDS && !command_is_a_response) {
+                // Door API.
+                llMessageLinked(LINK_SET, listenChannel, "cmd|door|open", llGetKey());
+            }
+            command_is_a_response = FALSE;  // took care of that one.
+        }
+        else
+        {
+if (DEBUGGING) llOwnerSay("closing the door.");
+            if (doorCloseSound != "")
+            {
+                llTriggerSound(doorCloseSound, 1.0);
+            }
+            jump_to_position(closedPos, closedRot);
+//            list config_blast = [ 
+//                PRIM_ROTATION, ZERO_ROTATION * closedRot / llGetRootRotation(),
+//                PRIM_POSITION, closedPos
+////                PRIM_SIZE, llGetScale()
+//                ];
+//            llSetPrimitiveParams(config_blast);
+//if (DEBUGGING) llOwnerSay("want pos=" + (string)closedPos + ", got=" + (string)llGetLocalPos()
+//+ ", and want rot=" + (string)closedRot + ", got=" + (string)llGetLocalRot());
+            if (PASS_COMMANDS && !command_is_a_response) {
+                // Door API.
+                llMessageLinked(LINK_SET, listenChannel, "cmd|door|close", llGetKey());
+            }
+            command_is_a_response = FALSE;  // took care of that one.
+        }
+        
+        llSetTimerEvent(0.0);
+        if (isOpen == TRUE && autoCloseTime != 0.0)
+        {
+            llSetTimerEvent(autoCloseTime);
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns text for a floating point number, but includes only
+// three digits after the decimal point.
+string float_chop(float to_show)
+{
+    integer mant = llAbs(llRound(to_show * 1000.0) / 1000);
+    string neg_sign;
+    if (to_show < 0.0) neg_sign = "-";
+    string dec_s = (string)((llRound(to_show * 1000.0) - mant * 1000) / 1000.0);
+    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
+    // strip off all trailing zeros.
+    while (llGetSubString(dec_s, -1, -1) == "0")
+        dec_s = llDeleteSubString(dec_s, -1, -1);
+    string to_return = neg_sign + (string)mant;
+    if (llStringLength(dec_s)) to_return += "." + dec_s;
+    return to_return;
+}
+
+// returns a prettier form for vector text, with chopped floats.
+string vector_chop(vector to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ">";
+}
+
+// similarly, for a rotation.
+string rotation_chop(rotation to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ","
+        + float_chop(to_show.s) + ">";
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        listenHandle = llListen(listenChannel, "", NULL_KEY, "");
+        myGetDoorParams();
+        myCloseDoor();
+    }
+    
+    on_rez(integer parm) { llResetScript(); }
+
+    touch_start(integer total_number)
+    {
+        command_is_a_response = FALSE;
+        if (myPermissionCheck(llDetectedKey(0)) == TRUE)
+        {
+            avatarName = llDetectedName(0);
+            myToggleDoor();
+        }
+        else
+        {
+            mySoundAccessDenied();
+        }
+    }
+    
+    timer()
+    {
+        myCloseDoor();
+    }
+    
+    link_message(integer sender_num, integer num, string str, key id)
+    {
+        // Door API. The API is here in case you want to create PIN entry keypads or whatever.
+        if (num == listenChannel) {
+            if (id == llGetKey()) return;  // don't listen to our own commands.
+            command_is_a_response = TRUE;
+            if (str == "cmd|door|open") myOpenDoor();
+            else if (str == "cmd|door|close") myCloseDoor();
+            else if (str == "cmd|door|discover")
+                llMessageLinked(LINK_SET, listenChannel, "cmd|door|discovered|" + (string)llGetKey(),
+                    llGetKey());
+            else command_is_a_response = FALSE;
+//hmmm: above protocol seems redundant, but sending back the original id (like this did before)
+//      in the id field does not fit in with our usual schemes very well.
+        }
+    }
+    
+    listen(integer channel, string name, key id, string message)
+    {
+//        if (DEBUGGING) llOwnerSay("heard: " + message);
+        command_is_a_response = FALSE;  // don't get involved with the link message checking.
+
+        // Performance note: it's quicker to compare the strings than to compare permissions each time anyone says anything on this channel.
+        if (message == "open")
+        {
+            if (myPermissionCheck(id) == TRUE)
+            {
+                // Only open the door if the person is quite close to this door.
+                openerKey = id;
+                closerKey = NULL_KEY;
+                avatarName = name;
+                llSensor(name, id, AGENT, RESPONSE_DISTANCE, TWO_PI);
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+        else if (message == "close")
+        {
+            if (myPermissionCheck(id) == TRUE)
+            {
+                openerKey = NULL_KEY;
+                closerKey = id;
+                avatarName = name;
+                // Only close the door if the person is quite close to this door.
+                llSensor(name, id, AGENT, RESPONSE_DISTANCE, TWO_PI);
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+        else if (message == "lock")
+        {
+            if (myPermissionCheck(id) == TRUE)
+            {
+                isLocked = TRUE;
+                mySoundConfirmed();
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+        else if (message == "unlock")
+        {
+            if (myPermissionCheck(id) == TRUE)
+            {
+                isLocked = FALSE;
+                mySoundConfirmed();
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+        else if (message == "toggle")
+        {
+            if (myPermissionCheck(id) == TRUE)
+            {
+                avatarName = name;
+                myToggleDoor();
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+        else if (message == "/door opened" && llSubStringIndex(llGetObjectName(), "D;") == -1)
+        {
+            if (llGetOwnerKey(id) == llGetOwner())
+            {
+                mySoundConfirmed();
+                openPos = llGetLocalPos();
+                openRot = llGetLocalRot();
+                isOpen = TRUE;
+                mySetDoorParams(TRUE, openPos, openRot);
+//llSay(0, "set open pos=" + (string)(openPos) + " rot=" + (string)(openRot));
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+        else if (message == "/door closed" && llSubStringIndex(llGetObjectDesc(), "D;") == -1)
+        {
+            if (llGetOwnerKey(id) == llGetOwner())
+            {
+                mySoundConfirmed();
+                closedPos = llGetLocalPos();
+                closedRot = llGetLocalRot();
+                isOpen = FALSE;
+                mySetDoorParams(FALSE, closedPos, closedRot);
+//llSay(0, "set close pos=" + (string)(closedPos) + " rot=" + (string)(closedRot));
+            }
+            else
+            {
+                mySoundAccessDenied();
+            }
+        }
+    }
+    
+    sensor(integer num_detected)
+    {
+        if (openerKey != NULL_KEY)
+        {
+            integer i;
+            for (i = 0; i < num_detected; i++)
+            {
+                if (llDetectedKey(i) == openerKey && myPermissionCheck(llDetectedKey(i)) == TRUE)
+                {
+                    myOpenDoor();
+                }
+            }
+            openerKey = NULL_KEY;
+        }
+        else
+        {
+            integer i;
+            for (i = 0; i < num_detected; i++)
+            {
+                if (llDetectedKey(i) == closerKey && myPermissionCheck(llDetectedKey(i)) == TRUE)
+                {
+                    myCloseDoor();
+                }
+            }
+            closerKey = NULL_KEY;
+        }
+    }
+
+//------------------------------------------------------
+// Uncomment the following code if you particularly want
+// collisions to affect the door state.    
+//------------------------------------------------------
+
+//    collision_start(integer num_detected)
+//    {
+//        integer i;
+//        for (i = 0; i < num_detected; i++)
+//        {
+//            if (myPermissionCheck(llDetectedKey(i)) == TRUE)
+//            {
+//                avatarName = llDetectedName(i);
+//                myOpenDoor();
+//            }
+//            else if (llDetectedType(i) & AGENT)
+//            {
+//                mySoundAccessDenied();
+//            }
+//        }
+//    }
+
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/TL_Door_fredmod_v4.4.txt b/huffware/huffotronic_updater_freebie_v5.3/TL_Door_fredmod_v4.4.txt
deleted file mode 100755 (executable)
index 0255c6c..0000000
+++ /dev/null
@@ -1,697 +0,0 @@
-
-// fred huffhines mods:
-//
-// took away the universal skeleton key that was lodged in this script.
-//
-// stopped considering door's scale; this is not usually needed, plus we were blowing
-//      past the SL limit on object names.
-//
-// moved to only storing a couple digits after the decimal point; this is another
-//      crucial thing to limit the size of the object name.
-//
-// added a "toggle" command that behaves like touch, in that the door will be opened
-//      or closed based on current state.
-//
-// made the sensor distance required before the door will listen to someone into a
-//      configurable parameter, instead of the woefully tiny, hard-coded 5 meters.
-//
-// added debugging flag and switchable logging for debugging mode.
-//
-// *original license and author info below...*
-//
-// plus, timeless prototype said this about using the script in osgrid and elsewhere:
-//      "hi, thanks for asking, yes you may use the door script in other grids."
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-// more fred huffhines mods: (circa march 2012)
-//   added PASS_COMMANDS flag, which can be used to pass along any commands we
-// hear to anyone else on our same channel within the object.
-//   added stifling of commands heard so they don't get re-sent, causing endless
-// loops of door openings.
-
-
-//------------------------------------------------------
-// Timeless Linked Door Script by Timeless Prototype
-//------------------------------------------------------
-// The latest version of this script can always be found
-// in the Library section of the wiki:
-// http://www.secondlife.com/badgeo/
-// This script is free to use, but whereever it is used
-// the SCRIPT's permissions MUST be set to:
-// [x] Next owner can modify
-// [x] Next owner can copy
-// [x] Next owner can transfer
-// [x] Allow anyone to copy
-// [x] Share with group
-
-//------------------------------------------------------
-// USAGE INSTRUCTIONS FOR EVERYDAY USE:
-//------------------------------------------------------
-// Say the following commands on channel 0:
-// 'unlock'     - Unlocks all doors in range.
-// 'lock'       - Locks all doors in range and allows
-//                only the permitted users to open it.
-// To open the door, either Touch it, Walk into it or
-// say 'open' or say 'close'.
-
-//------------------------------------------------------
-// USAGE INSTRUCTIONS FOR BUILDERS:
-//------------------------------------------------------
-// 1. Copy and paste this script into the door prim and
-//    change the settings (see further down).
-// 2. The door prim must be linked to at least one other
-//    prim (could be linked to the house for example).
-// 3. The door prim MUST NOT be the root prim.
-// 4. Use Edit Linked Parts to move, rotate and size the
-//    door prim for the closed state.
-// 5. When ready, stand close to the door and say
-//    '/door closed' (this records the closed door
-//    position, rotation and size to the object's
-//    name and description).
-// 6. Use the Edit Linked parts to move, rotate and size
-//    the door prim for the opened state.
-// 7. When ready, stand close to the door and say
-//    '/door opened' (this records the opened door
-//    position, rotation and size).
-// 8. Once recorded it will not accept these commands
-//    again. If you do need to redo the settings then
-//    delete the Name and Description of the door prim
-//    (these are where the position information is
-//    stored), and then follow the steps above again.
-//    Note: deleting the object name won't save, so set
-//    the object name to 'Object' to reset the object
-//    name.
-
-//------------------------------------------------------
-// Change these settings to suit your needs.
-//------------------------------------------------------
-// To mute any/all of the sounds set the sound string(s)
-// to "" (empty string).
-// To get the UUID of a sound, right click on the sound
-// in your inventory and choose "Copy Asset UUID", then
-// paste the UUID in here.
-string      doorOpenSound       = "Door open";
-string      doorCloseSound      = "Door close";
-string      confirmedSound      = "69743cb2-e509-ed4d-4e52-e697dc13d7ac";
-string      accessDeniedSound   = "58da0f9f-42e5-8a8f-ee51-4fac6c247c98";
-string      doorBellSound       = ""; // Setting to empty stops door announcements too.
-float       autoCloseTime       = 120.0; // 0 seconds to disable auto close.
-integer     allowGroupToo       = TRUE; // Set to FALSE to disallow same group access to door.
-list        allowedAgentUUIDs   = []; // Comma-separated, quoted list of avatar UUIDs who are allowed access to this door.
-// was allowing this sneaky guy: "8efecbac-35de-4f40-89c1-2c772b83cafa"
-integer     listenChannel       = 10106;
-float       RESPONSE_DISTANCE   = 120.0;  // how far to allow a command from users with permission.
-integer     DEBUGGING           = FALSE;
-integer     PASS_COMMANDS       = TRUE;
-    // if true, then we will order other doors to open when we do.
-    // we use the listenChannel as the id to pass commands on, so that only the doors listening to
-    // the same place will hear our commands.
-integer     command_is_a_response  = FALSE;
-    // if this is true, then the door open and close must not re-echo their actions.
-
-//------------------------------------------------------
-// Leave the rest of the settings alone, these are
-// handled by the script itself.
-//------------------------------------------------------
-integer     isLocked            = FALSE; // Only when the door is locked do the permissions apply.
-integer     isOpen              = TRUE;
-vector      openPos             = ZERO_VECTOR;
-rotation    openRot             = ZERO_ROTATION;
-vector      closedPos           = ZERO_VECTOR;
-rotation    closedRot           = ZERO_ROTATION;
-key         openerKey           = NULL_KEY;
-key         closerKey           = NULL_KEY;
-integer     isSetup             = FALSE;
-integer     listenHandle        = 0;
-string      avatarName          = "";
-
-// zooms the sub-prim to a new rotation and position.
-jump_to_position(vector position, rotation new_rot)
-{
-    list config_blast = [ 
-        PRIM_SIZE, llGetScale(), ///????
-        // first jump away from where we started, trying to get past an opensim bug.
-//        PRIM_POSITION, ZERO_VECTOR,
-//        PRIM_POSITION, ZERO_VECTOR,
-//        PRIM_POSITION, ZERO_VECTOR,
-//        PRIM_POSITION, ZERO_VECTOR,
-//        PRIM_POSITION, ZERO_VECTOR,
-        PRIM_ROTATION, ZERO_ROTATION * new_rot / llGetRootRotation(),
-//        PRIM_POSITION, position,
-//        PRIM_POSITION, position,
-//        PRIM_POSITION, position,
-//        PRIM_POSITION, position,
-//        PRIM_POSITION, position,
-        PRIM_POSITION, position
-        ];
-    llSetLinkPrimitiveParams(llGetLinkNumber(), config_blast);
-if (DEBUGGING) llOwnerSay("want pos=" + (string)position + ", got=" + (string)llGetLocalPos()
-+ ", and want rot=" + (string)new_rot + ", got=" + (string)llGetLocalRot());
-}
-
-mySayName(integer channel, string objectName, string message)
-{
-    string name = llGetObjectName();
-    llSetObjectName(objectName);
-    llSay(0, "/me " + message);
-    llSetObjectName(name);
-}
-
-mySay(integer channel, string message)
-{
-    string name = llGetObjectName();
-    llSetObjectName("Door");
-    llSay(0, message);
-    llSetObjectName(name);
-}
-
-myOwnerSay(string message)
-{
-    string name = llGetObjectName();
-    llSetObjectName("Door");
-    llOwnerSay(message);
-    llSetObjectName(name);
-}
-
-mySoundConfirmed()
-{
-    if (confirmedSound != "")
-    {
-        llTriggerSound(confirmedSound, 1.0);
-    }
-}
-
-mySoundAccessDenied()
-{
-    if (accessDeniedSound != "")
-    {
-        llTriggerSound(accessDeniedSound, 1.0);
-    }
-}
-
-myGetDoorParams()
-{
-    isSetup = FALSE;
-    if (llSubStringIndex(llGetObjectDesc(), "D;") == 0 && llSubStringIndex(llGetObjectName(), "D;") == 0)
-    {
-        list nameWords = llParseString2List(llGetObjectName(), [";"], []);
-        list descWords = llParseString2List(llGetObjectDesc(), [";"], []);
-        if (llGetListLength(nameWords) != 3 || llGetListLength(descWords) != 3)
-        {
-            myOwnerSay("The door prim's name and/or description has invalid syntax and/or number of parameters. Delete the door prim's name and description and setup the door prim again.");
-        }
-        else
-        {
-            openPos = (vector)llList2String(nameWords, 1);
-            openRot = (rotation)llList2String(nameWords, 2);
-            closedPos = (vector)llList2String(descWords, 1);
-            closedRot = (rotation)llList2String(descWords, 2);
-            isSetup = TRUE;
-        }
-//llSay(0, "got open pos=" + (string)(openPos) + " rot=" + (string)(openRot));
-//llSay(0, "got close pos=" + (string)(closedPos) + " rot=" + (string)(closedRot));
-        
-    }
-}
-
-// if open_state is true, the parms are for an open door.
-mySetDoorParams(integer open_state, vector Pos, rotation Rot)
-{
-    if (open_state) {
-        // parms for open state.
-        llSetObjectName("D;" + vector_chop(Pos) + ";" + rotation_chop(Rot));
-    } else {
-        // parms for closed state.
-        llSetObjectDesc("D;" + vector_chop(Pos) + ";" + rotation_chop(Rot));
-    }
-    isSetup = TRUE;
-}
-
-integer myPermissionCheck(key id)
-{
-    integer hasPermission = FALSE;
-    if (isLocked == FALSE) {
-        if (DEBUGGING) llOwnerSay("perm--unlocked: okay");
-        hasPermission = TRUE;
-    } else if (llGetOwnerKey(id) == llGetOwner()) {
-        if (DEBUGGING) llOwnerSay("perm--is owner: okay");
-        hasPermission = TRUE;
-    } else if (allowGroupToo == TRUE && llSameGroup(id)) {
-        if (DEBUGGING) llOwnerSay("perm--same group: okay");
-        hasPermission = TRUE;
-    } else if (llListFindList(allowedAgentUUIDs, [(string)id]) != -1) {
-        if (DEBUGGING) llOwnerSay("perm--in list: okay");
-        hasPermission = TRUE;
-    } else {
-        if (DEBUGGING) llOwnerSay("perm--not found anywhere: bad perms");
-    }
-    return hasPermission;
-}
-
-myOpenDoor()
-{
-    isOpen = FALSE;
-    myToggleDoor();
-}
-
-myCloseDoor()
-{
-    isOpen = TRUE;
-    myToggleDoor();
-}
-
-myToggleDoor()
-{
-    if (isSetup == FALSE)
-    {
-        myOwnerSay("The door prim has not been configured yet. Please read the usage instructions in the door script.");
-    }
-    else if (llGetLinkNumber() == 0 || llGetLinkNumber() == 1)
-    {
-        myOwnerSay("The door prim must be linked to at least one other prim and the door prim must not be the root prim");
-    }
-    else
-    {
-        isOpen = !isOpen;
-if (DEBUGGING) llOwnerSay("door open state is now=" + (string)isOpen);
-        if (isOpen)
-        {
-if (DEBUGGING) llOwnerSay("opening the door.");
-            if (doorBellSound != "")
-            {
-                llTriggerSound(doorBellSound, 1.0);
-                if (avatarName != "")
-                {
-                    mySayName(0, avatarName, "is at the door.");
-                    avatarName = "";
-                }
-            }
-            if (doorOpenSound != "")
-            {
-                llTriggerSound(doorOpenSound, 1.0);
-            }
-            jump_to_position(openPos, openRot);
-//            list config_blast = [ PRIM_POSITION, llGetLocalPos() + <4, 4, 4>,
-//                PRIM_ROTATION, ZERO_ROTATION * openRot / llGetRootRotation(),
-//                PRIM_POSITION, openPos
-////                PRIM_SIZE, llGetScale() 
-//                ];
-//            llSetPrimitiveParams(config_blast);
-//if (DEBUGGING) llOwnerSay("want pos=" + (string)openPos + ", got=" + (string)llGetLocalPos()
-//+ ", and want rot=" + (string)openRot + ", got=" + (string)llGetLocalRot());
-
-            if (PASS_COMMANDS && !command_is_a_response) {
-                // Door API.
-                llMessageLinked(LINK_SET, listenChannel, "cmd|door|open", llGetKey());
-            }
-            command_is_a_response = FALSE;  // took care of that one.
-        }
-        else
-        {
-if (DEBUGGING) llOwnerSay("closing the door.");
-            if (doorCloseSound != "")
-            {
-                llTriggerSound(doorCloseSound, 1.0);
-            }
-            jump_to_position(closedPos, closedRot);
-//            list config_blast = [ 
-//                PRIM_ROTATION, ZERO_ROTATION * closedRot / llGetRootRotation(),
-//                PRIM_POSITION, closedPos
-////                PRIM_SIZE, llGetScale()
-//                ];
-//            llSetPrimitiveParams(config_blast);
-//if (DEBUGGING) llOwnerSay("want pos=" + (string)closedPos + ", got=" + (string)llGetLocalPos()
-//+ ", and want rot=" + (string)closedRot + ", got=" + (string)llGetLocalRot());
-            if (PASS_COMMANDS && !command_is_a_response) {
-                // Door API.
-                llMessageLinked(LINK_SET, listenChannel, "cmd|door|close", llGetKey());
-            }
-            command_is_a_response = FALSE;  // took care of that one.
-        }
-        
-        llSetTimerEvent(0.0);
-        if (isOpen == TRUE && autoCloseTime != 0.0)
-        {
-            llSetTimerEvent(autoCloseTime);
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns text for a floating point number, but includes only
-// three digits after the decimal point.
-string float_chop(float to_show)
-{
-    integer mant = llAbs(llRound(to_show * 1000.0) / 1000);
-    string neg_sign;
-    if (to_show < 0.0) neg_sign = "-";
-    string dec_s = (string)((llRound(to_show * 1000.0) - mant * 1000) / 1000.0);
-    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
-    // strip off all trailing zeros.
-    while (llGetSubString(dec_s, -1, -1) == "0")
-        dec_s = llDeleteSubString(dec_s, -1, -1);
-    string to_return = neg_sign + (string)mant;
-    if (llStringLength(dec_s)) to_return += "." + dec_s;
-    return to_return;
-}
-
-// returns a prettier form for vector text, with chopped floats.
-string vector_chop(vector to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ">";
-}
-
-// similarly, for a rotation.
-string rotation_chop(rotation to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ","
-        + float_chop(to_show.s) + ">";
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        listenHandle = llListen(listenChannel, "", NULL_KEY, "");
-        myGetDoorParams();
-        myCloseDoor();
-    }
-    
-    on_rez(integer parm) { llResetScript(); }
-
-    touch_start(integer total_number)
-    {
-        command_is_a_response = FALSE;
-        if (myPermissionCheck(llDetectedKey(0)) == TRUE)
-        {
-            avatarName = llDetectedName(0);
-            myToggleDoor();
-        }
-        else
-        {
-            mySoundAccessDenied();
-        }
-    }
-    
-    timer()
-    {
-        myCloseDoor();
-    }
-    
-    link_message(integer sender_num, integer num, string str, key id)
-    {
-        // Door API. The API is here in case you want to create PIN entry keypads or whatever.
-        if (num == listenChannel) {
-            if (id == llGetKey()) return;  // don't listen to our own commands.
-            command_is_a_response = TRUE;
-            if (str == "cmd|door|open") myOpenDoor();
-            else if (str == "cmd|door|close") myCloseDoor();
-            else if (str == "cmd|door|discover")
-                llMessageLinked(LINK_SET, listenChannel, "cmd|door|discovered|" + (string)llGetKey(),
-                    llGetKey());
-            else command_is_a_response = FALSE;
-//hmmm: above protocol seems redundant, but sending back the original id (like this did before)
-//      in the id field does not fit in with our usual schemes very well.
-        }
-    }
-    
-    listen(integer channel, string name, key id, string message)
-    {
-//        if (DEBUGGING) llOwnerSay("heard: " + message);
-        command_is_a_response = FALSE;  // don't get involved with the link message checking.
-
-        // Performance note: it's quicker to compare the strings than to compare permissions each time anyone says anything on this channel.
-        if (message == "open")
-        {
-            if (myPermissionCheck(id) == TRUE)
-            {
-                // Only open the door if the person is quite close to this door.
-                openerKey = id;
-                closerKey = NULL_KEY;
-                avatarName = name;
-                llSensor(name, id, AGENT, RESPONSE_DISTANCE, TWO_PI);
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-        else if (message == "close")
-        {
-            if (myPermissionCheck(id) == TRUE)
-            {
-                openerKey = NULL_KEY;
-                closerKey = id;
-                avatarName = name;
-                // Only close the door if the person is quite close to this door.
-                llSensor(name, id, AGENT, RESPONSE_DISTANCE, TWO_PI);
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-        else if (message == "lock")
-        {
-            if (myPermissionCheck(id) == TRUE)
-            {
-                isLocked = TRUE;
-                mySoundConfirmed();
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-        else if (message == "unlock")
-        {
-            if (myPermissionCheck(id) == TRUE)
-            {
-                isLocked = FALSE;
-                mySoundConfirmed();
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-        else if (message == "toggle")
-        {
-            if (myPermissionCheck(id) == TRUE)
-            {
-                avatarName = name;
-                myToggleDoor();
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-        else if (message == "/door opened" && llSubStringIndex(llGetObjectName(), "D;") == -1)
-        {
-            if (llGetOwnerKey(id) == llGetOwner())
-            {
-                mySoundConfirmed();
-                openPos = llGetLocalPos();
-                openRot = llGetLocalRot();
-                isOpen = TRUE;
-                mySetDoorParams(TRUE, openPos, openRot);
-//llSay(0, "set open pos=" + (string)(openPos) + " rot=" + (string)(openRot));
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-        else if (message == "/door closed" && llSubStringIndex(llGetObjectDesc(), "D;") == -1)
-        {
-            if (llGetOwnerKey(id) == llGetOwner())
-            {
-                mySoundConfirmed();
-                closedPos = llGetLocalPos();
-                closedRot = llGetLocalRot();
-                isOpen = FALSE;
-                mySetDoorParams(FALSE, closedPos, closedRot);
-//llSay(0, "set close pos=" + (string)(closedPos) + " rot=" + (string)(closedRot));
-            }
-            else
-            {
-                mySoundAccessDenied();
-            }
-        }
-    }
-    
-    sensor(integer num_detected)
-    {
-        if (openerKey != NULL_KEY)
-        {
-            integer i;
-            for (i = 0; i < num_detected; i++)
-            {
-                if (llDetectedKey(i) == openerKey && myPermissionCheck(llDetectedKey(i)) == TRUE)
-                {
-                    myOpenDoor();
-                }
-            }
-            openerKey = NULL_KEY;
-        }
-        else
-        {
-            integer i;
-            for (i = 0; i < num_detected; i++)
-            {
-                if (llDetectedKey(i) == closerKey && myPermissionCheck(llDetectedKey(i)) == TRUE)
-                {
-                    myCloseDoor();
-                }
-            }
-            closerKey = NULL_KEY;
-        }
-    }
-
-//------------------------------------------------------
-// Uncomment the following code if you particularly want
-// collisions to affect the door state.    
-//------------------------------------------------------
-
-//    collision_start(integer num_detected)
-//    {
-//        integer i;
-//        for (i = 0; i < num_detected; i++)
-//        {
-//            if (myPermissionCheck(llDetectedKey(i)) == TRUE)
-//            {
-//                avatarName = llDetectedName(i);
-//                myOpenDoor();
-//            }
-//            else if (llDetectedType(i) & AGENT)
-//            {
-//                mySoundAccessDenied();
-//            }
-//        }
-//    }
-
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/a_huffotronic_update_server_v23.2.lsl b/huffware/huffotronic_updater_freebie_v5.3/a_huffotronic_update_server_v23.2.lsl
new file mode 100755 (executable)
index 0000000..ef201cf
--- /dev/null
@@ -0,0 +1,940 @@
+
+// huffware script: huff-update server, by fred huffhines.
+//
+// this script is the server side of the update process.  it should reside in an object that
+// has all the newest versions of scripts and objects that will be updated.  when rezzed, and
+// at periodic intervals, it announces on a private chat channel that updates are available.
+// when objects respond that they might like an update, it tells them the scripts that it has
+// stored inside of it.  if any of those scripts are an older version inside the client
+// (update requesting) object, then the client will request the newer versions.  the server
+// object will stuff them into it and tell them to start running.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer IS_OPENSIM = TRUE;  // must be set to true for opensim, false for second life.
+
+integer DEBUGGING = FALSE;  // set this to true for noisier diagnostics.
+
+
+
+// updater dependency section:
+// should be moved to a notecard!!!
+//
+// format is a list of strings, where each string has a pair wrapped by the
+// huffware item separators.  the pair contains (1) the basename of a script
+// that has a new dependency and (2) the basename of that new dependency.
+list known_script_dependencies;
+
+
+
+
+load_script_deps()
+{
+    known_script_dependencies = [
+        llDumpList2String(["jaunt wik rez", "jaunt config funcs"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["jaunt wik rez", "data cow"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["jaunt wik rez", "jaunt rezolator"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["remotely personable", "inventory exchanger"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "exchange driver hudimation"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "avatar timer manager"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["animote main driver", "avatar choice memory"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["giftorse", "particle projector"], ITEM_LIST_SEPARATOR),
+        llDumpList2String(["huff-search brainiac", "searchbert armature"], ITEM_LIST_SEPARATOR),
+
+        
+//special purpose -- removes the updater from the elevator buttons...
+//llDumpList2String(["comfortable sitting", "zap updater from elevators"], ITEM_LIST_SEPARATOR),
+// => do not uncomment unless you want your elevators to shed their ability to update.
+
+
+        // this allows us to add or remove items above at will without complaints about comma.
+        llDumpList2String(["xyzzy", "hopefully-never-matches"], ITEM_LIST_SEPARATOR)
+    ];
+}
+
+
+
+
+// global constants...
+
+integer USER_COMMAND_CHANNEL = 4;  // channel where we listen to user commands.
+
+float ANNOUNCEMENT_PERIOD = 14.0;  // how often we tell other objects that we have tasty treats.
+
+integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
+integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
+
+string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
+string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
+string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
+string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
+string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
+string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
+string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
+string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
+string DONE_UPDATING                = "#finito#";  // the client is done updating.
+string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
+
+integer UPDATER_SCRIPT_PIN          = -1231008;  // the hook for our scripts to be modified.
+
+string RESTART_UPDATER_COMMAND      = "#restart";  // said in open chat to recrank the updater.
+string SHOW_SCRIPTS_COMMAND         = "#show";  // said in open chat to list out the scripts.
+string SHUTDOWN_COMMAND             = "#destroy";  // shuts down object and destroys it.
+
+string UPDATER_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+
+string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
+
+integer ENTRIES_PER_LINE = 4;  // number of items from a list shown on one line of text.
+
+integer MAXIMUM_ACTIVE_CLIENTS = 5;  // number of conversations we will allow at a time.
+
+float LONGEST_SLACK_PER_CLIENT = 84.0;
+    // we allow a client to be out of touch with us for this many seconds.  after that,
+    // we decide it's deceased and remove it from our list.
+
+integer MESSAGE_SIZE_LIMIT = 800;  // longest thing that can be safely said without clipping (guess).
+
+float SCRIPT_LIST_PAUSE_INTERVAL = 1.4;  // pause between large chunks of update text.
+
+string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
+
+float CHANGED_INVENTORY_SNOOZER = 7.0;
+    // the number of seconds we sleep once we see an inventory change.  we don't want to
+    // react to this immediately.  this overrides the normal announcement cycle until it's
+    // dealt with by the timer.
+
+string CONTINUANCE_MARKER = "...";
+    // a string sent when the update list is too long and needs to be continued in another chat.
+
+string UPDATER_BASE_NAME = "huff-update client";
+    // the name of the updater script that keeps everything in sync.
+
+//////////////
+
+// global variables...
+
+list scripts_available;  // the list of scripts we have in our inventory for distribution.
+list objects_available;  // list of objects for handing out.
+
+list active_clients;  // list of keys for clients that are updating currently.
+list active_update_channels;  // active conversations on client chosen channels.
+list active_listen_ids;  // the ids for the listener on those channels.
+list active_timestamps;  // tracks when the client was last active.
+
+integer inventory_request_channel;  // our personal channel that the update client should talk with.
+
+integer dealing_with_change;  // has the inventory changed?  we will deal with this in the timer.
+
+// displays the status of the update server.
+show_status(key who_says)
+{
+    string title = "[mem free=" + (string)llGetFreeMemory() + "]";
+    title = "Listening for requests on channel " + (string)inventory_request_channel;
+    if (llGetListLength(active_update_channels))
+        title += "\nactive channels="
+            + dump_list(active_update_channels, FALSE, ENTRIES_PER_LINE);
+    else
+        title += "\nNo channels active.";
+        
+    if (llGetListLength(active_clients))
+        title += "\nactive clients=" + dump_keyed_list(active_clients, TRUE, 2);
+    else
+        title += "\nNo clients active.";
+    
+    if (llGetOwner() == who_says) {
+        string addition = " ";
+        if (USER_COMMAND_CHANNEL != 0) addition = "/" + (string)USER_COMMAND_CHANNEL + " ";
+        title += "\n[ \"" + addition + SHOW_SCRIPTS_COMMAND + "\" lists all the scripts, "
+            + "\"" + addition + SHUTDOWN_COMMAND + "\" zaps the updater, "
+            + "\"" + addition + RESTART_UPDATER_COMMAND + "\" refreshes the updater ]";
+    }
+
+    llWhisper(0, title);
+}
+
+// plink a quietous string of resonance...
+squonk(integer indy)
+{
+    string snd = llGetInventoryName(INVENTORY_SOUND, indy);
+    if (snd != "") llTriggerSound(snd, 1.0);
+}
+
+// list out the scripts that the server's object contains.
+show_scripts()
+{
+    string title = (string)llGetListLength(scripts_available) + " scripts available:";
+    show_list(title, scripts_available);
+    title = (string)llGetListLength(objects_available) + " objects available:";
+    show_list(title, objects_available);
+}
+
+// lets the client know that we're here and have some scripts available.
+announce_presence()
+{
+    if (llGetListLength(active_clients) < MAXIMUM_ACTIVE_CLIENTS) {
+        // only announce if we're not already booked up.
+        llWhisper(UPDATE_ANNOUNCEMENT_CHANNEL, UPDATE_ANNOUNCEMENT_PREFIX + (string)inventory_request_channel);
+    }
+}
+
+// lifted from "clear text and effects" script; should be nearly identical
+// to that, except that we set the texture animation.
+reset_all_effects()
+{
+    llSetText("", <0,0,0>, 0);  // clear any text above object.
+    llSetSitText("Sit Here");  // reset sit text to default state.
+    llSetTouchText("Touch");  // similarly for touch.
+    llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
+    llParticleSystem([]);  // turn off all particles.
+    llSensorRemove();  // stop any running sensors.
+    llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
+    llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
+    // keep it from being physical and from disapparating.
+    llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE,
+        PRIM_PHANTOM, TRUE]);
+    llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
+
+    //
+    // the following are specific to the huffotronic update server.
+    //
+
+    // we re-assert our special texture set here, in case some wayward scripts have
+    // messed with us.
+    integer textures_held = llGetInventoryNumber(INVENTORY_TEXTURE);
+    integer indy;
+    for (indy = 0; indy < textures_held; indy++) {
+        string curr_tex = llGetInventoryName(INVENTORY_TEXTURE, indy);
+        // we have a simple scheme for putting textures on the updater.
+        // we have an inside, an outside and the ends.
+        if (is_prefix(curr_tex, "~~s0")) {
+            llSetTexture(curr_tex, ALL_SIDES);
+        } else if (is_prefix(curr_tex, "~~s1")) {
+            llSetTexture(curr_tex, 1);
+        } else if (is_prefix(curr_tex, "~~s2")) {
+            llSetTexture(curr_tex, 0);
+            llSetTexture(curr_tex, 3);
+        }
+    }
+    
+    // re-assert our texture animation also.
+    llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE,
+        ALL_SIDES, 0, 0, 0, TWO_PI, 1.0 / 36.0);
+}
+
+// set up the update server object.
+initialize_root()
+{
+    // set up our particular "look".
+    reset_all_effects();
+
+    // shut down any competing scripts in this object.
+    // we try to swat any other script that's been added before we let them do weird
+    // stuff.  for example, a pet script might start acting like one.  this
+    // function is not guaranteed to run before that bad stuff can happen,
+    // and that's maybe the one major issue with this approach.  as long as
+    // the contained scripts aren't evil (like if they jump someplace else
+    // as soon as they start), then there shouldn't be any serious problems.
+    knock_down_other_scripts();
+
+    // reset our variables.
+    active_update_channels = [];
+    active_listen_ids = [];
+    active_clients = [];
+    active_timestamps = [];
+    scripts_available = [];
+    objects_available = [];
+    dealing_with_change = FALSE;  // not handling any inventory changes.
+
+    // make sure we know about any scripts that have new dependencies.
+    load_script_deps();
+
+    // clean out any older versions of the scripts before we make our
+    // inventory.
+    destroy_older_versions();
+
+    // now accumulate the list of scripts in our inventory.    
+    integer items_held = llGetInventoryNumber(INVENTORY_SCRIPT);
+    integer indy;
+    for (indy = 0; indy < items_held; indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        // we don't provide our own script for updating; it must be kept from
+        // floating around, like into other objects that are not updaters.
+////        if (curr_script != llGetScriptName())
+            scripts_available += curr_script;
+    }
+    items_held = llGetInventoryNumber(INVENTORY_OBJECT);
+    for (indy = 0; indy < items_held; indy++) {
+        objects_available += llGetInventoryName(INVENTORY_OBJECT, indy);
+//log_it("added obj: " + llGetInventoryName(INVENTORY_OBJECT, indy));
+    }
+    items_held = llGetInventoryNumber(INVENTORY_NOTECARD);
+    for (indy = 0; indy < items_held; indy++) {
+        objects_available += llGetInventoryName(INVENTORY_NOTECARD, indy);
+//log_it("added note: " + llGetInventoryName(INVENTORY_NOTECARD, indy));
+    }
+
+    // listen to the owner.
+    llListen(USER_COMMAND_CHANNEL, "", llGetOwner(), "");
+    // listen for any requests from our loyal clients.
+    inventory_request_channel = random_channel();
+    llListen(inventory_request_channel, "", NULL_KEY, "");
+    // listen for older clients too.
+    llListen(OLD_REQUEST_INVENTORY_CHANNEL, "", NULL_KEY, "");
+
+    // set up the periodic announcements.
+    llSetTimerEvent(ANNOUNCEMENT_PERIOD);
+}
+
+handle_timer()
+{
+    if (dealing_with_change) {
+        dealing_with_change = FALSE;
+        state rerun;  // zoom back to the starting point.
+    }
+    integer indy;
+    integer timecheck = llGetUnixTime();  // use for whole loop.
+    for (indy = llGetListLength(active_timestamps) - 1; indy >= 0; indy--) {
+        integer last_time = llList2Integer(active_timestamps, indy);
+        if (llAbs(last_time - timecheck) > LONGEST_SLACK_PER_CLIENT) {
+            // we need to clear out this item.  we know we can whack the client
+            // at the same index and that will take care of this slacker.
+            key curr_key = llList2Key(active_clients, indy);
+            log_it("timed-out client: " + llKey2Name(curr_key) + " [" + (string)curr_key + "]");
+            remove_client(curr_key);
+        }
+    }
+
+    // let the objects nearby know that we are open for business by
+    // announcing the script inventory.
+    announce_presence();
+}
+
+// turns a list into a nicely formatted string.
+string dump_list(list to_show, integer initial_line_break, integer entries_per_line)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we break every Nth entry, but not if it's the first line and
+        // they said to not have the initial line break.
+        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
+            msg += "\n";
+        string cursc = llList2String(to_show, indy);
+        msg += cursc;
+        // add commas where needed.
+        if (indy < llGetListLength(to_show) - 1)
+            msg += ", ";
+    }
+    return msg;
+}
+
+// similar to dump_keyed_list, but only shows the names, each on their own line.
+string dump_names_for_keys(list to_show)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we only line break after the first entry.
+        if (indy > 0) msg += "\n";
+        string keystr = llList2String(to_show, indy);
+        msg += llKey2Name(keystr);
+    }
+    return msg;
+}
+
+// similar to dump_list
+string dump_keyed_list(list to_show, integer initial_line_break, integer entries_per_line)
+{
+    string msg;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(to_show); indy++) {
+        // we break every Nth entry, but not if it's the first line and
+        // they said to not have the initial line break.
+        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
+            msg += "\n";
+        string keystr = llList2String(to_show, indy);
+        msg += llKey2Name(keystr) + " (" + keystr + ")";
+        // add commas where needed.
+        if (indy < llGetListLength(to_show) - 1)
+            msg += ", ";
+    }
+    return msg;
+}
+
+// shows the list specified in a compact manner.
+show_list(string title, list to_show)
+{
+    string to_say = title + dump_list(to_show, TRUE, ENTRIES_PER_LINE);
+    // flush some memory.
+    title = "";
+    to_show = [];
+    integer indy;
+    // say the output in pieces to avoid over-clogging chat.
+    for (indy = 0; indy < llStringLength(to_say); indy += MESSAGE_SIZE_LIMIT) {
+        integer last_indy = indy + MESSAGE_SIZE_LIMIT - 1;
+        string addition;
+        if (last_indy < llStringLength(to_say)) addition = CONTINUANCE_MARKER;
+        llWhisper(0, llGetSubString(to_say, indy, last_indy) + addition);
+    }
+}
+
+// stops all the scripts besides this one.
+knock_down_other_scripts()
+{
+    // set all scripts but this to not be running.
+    integer indy;
+    string self_script = llGetScriptName();
+    list split = compute_basename_and_version(self_script);
+    string self_base = llList2String(split, 0);
+    self_script = ""; split = [];  // free memory.
+    integer count = llGetInventoryNumber(INVENTORY_SCRIPT);
+    // we set all other scripts that are not versions of this script to not be running.
+    for (indy = 0; indy < count; indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if (!is_prefix(curr_script, self_base)
+            && !is_prefix(curr_script, UPDATER_BASE_NAME) ) {
+            llSetScriptState(curr_script, FALSE);
+        }
+    }
+}
+
+// set a text label on the updater with the list of clients.
+set_our_label()
+{
+    string label = "";
+    if (llGetListLength(active_clients) > 0) label = "[updating]\n";
+    llSetText(label + dump_names_for_keys(active_clients), <0.8, 0.95, 0.92>, 1.0);
+}
+
+// clean out a client that we should be done with.
+remove_client(key id)
+{
+    // locate said client of deceased nature...
+    integer indy = find_in_list(active_clients, id);
+    if (indy < 0) {
+//        if (DEBUGGING) log_it("failure to find client to remove: " + (string)id);
+        return;
+    }
+    active_clients = llDeleteSubList(active_clients, indy, indy);
+    // also clean out the channel and stop listening to it.
+integer act_chan = llList2Integer(active_update_channels, indy);
+    active_update_channels = llDeleteSubList(active_update_channels, indy, indy);
+    integer listen_to_remove = llList2Integer(active_listen_ids, indy);
+//log_it("remove listen " + (string)listen_to_remove + " on chan " + (string)act_chan);
+    llListenRemove(listen_to_remove);
+    active_listen_ids = llDeleteSubList(active_listen_ids, indy, indy);
+    active_timestamps = llDeleteSubList(active_timestamps, indy, indy);
+    set_our_label();
+}
+
+// fix a partial match to a script name if we can't find the exact item.
+string backpatch_script_name(string partial)
+{
+    if (llGetInventoryType(partial) == INVENTORY_SCRIPT) return partial;  // all set.
+    integer dep_indy;
+    for (dep_indy = 0; dep_indy < llGetInventoryNumber(INVENTORY_SCRIPT); dep_indy++) {
+        string curr_name = llGetInventoryName(INVENTORY_SCRIPT, dep_indy);
+        if (is_prefix(curr_name, partial)) {
+//            log_it("found real name " + curr_name + " for part: " + partial);
+            return curr_name;
+        }
+    }
+//    log_it("no matches for partial script name!");
+    return "";  // no matches!
+}
+
+// moves the upgrade process with "id" along to the next step given the request in
+// the message.
+propel_upgrade_process(integer channel, key id, string message)
+{
+    if (DEBUGGING) log_it("got upgrade note from " + (string)id + " with msg=" + message);
+    if (message == REQUEST_SCRIPT_UPDATE) {
+        // begins the update process with the client.
+        llSay(channel, SHUT_THEM_DOWN);
+    } else if (is_prefix(message, READY_TO_UPDATE)) {
+        // whack the prefix so we can get the list they want.
+        message = llDeleteSubString(message, 0, llStringLength(READY_TO_UPDATE) - 1);
+        list requests = llParseString2List(message, [UPDATER_PARM_SEPARATOR], []);
+        message = "";
+        // send over the scripts the client asked for, since it seems to be ready for them.
+        if (llGetListLength(requests)) {
+            show_list("updating " + llKey2Name(id) + " (key " + (string)id + ") with", requests);
+            integer indy;
+            for (indy = 0; indy < llGetListLength(requests); indy++) {
+                string curr = llList2String(requests, indy);
+                if (find_in_list(objects_available, curr) >= 0) {
+//log_it("handing object over: " + curr);
+                    // it's an object, so treat it that way.
+                    llGiveInventory(id, curr);
+                } else {
+//log_it("handing script over: " + curr);
+                    // assume it's a script, and use script pin to stuff it.
+                    curr = backpatch_script_name(curr);
+                    if (curr != "") {
+//                        integer starting_state = FALSE;
+// second life was okay with scripts being plugged in unstarted.  opensim is not.
+// and second life appears to be unhappy with scripts plugged in as started.  so we
+// have an impasse.
+// this should be: true for opensim, and false for second life.
+                        integer starting_state = IS_OPENSIM;
+//                        if (DEBUGGING) log_it("installing script using updater pin.");
+                        llRemoteLoadScriptPin(id, curr, UPDATER_SCRIPT_PIN, starting_state, 0);
+                    }
+                }
+            }
+        }
+    } else if (message == SCRIPTS_ARE_CURRENT) {
+        // the client thinks it's ready to get back up and running.
+//log_it("heard client is ready!");
+        llSay(channel, START_THEM_UP);
+        // kludge for older clients (pre 10.4 version) to try to help them start up.
+//old and not useful.        llSleep(0.2); llSay(channel, START_THEM_UP); llSleep(0.2); llSay(channel, START_THEM_UP);
+        remove_client(id);
+    } else if (message == DONE_UPDATING) {
+        // this client has nothing to do for now.
+//log_it("heard client is done: " + (string)id);
+        remove_client(id);
+    } else {
+//log_it("weird note from client: " + message);
+        return;  // not used.
+    }
+    
+}
+
+// blasts out the inventory list to a curious client.
+spew_inventory_list(integer channel, string message, key id)
+{
+    if (!is_prefix(message, REQUEST_INVENTORY_PREFIX)) {
+
+        // this is an old style update alert that we still use at startup of the client
+        // to ensure that finishing replacement of the updater script is never unnoticed.
+        if (is_prefix(message, DONE_UPDATING)) {
+//            if (DEBUGGING) log_it("found very special message from startup of updater.");
+            propel_upgrade_process(channel, id, message);
+        }
+        
+        // argh, this is not the right kind of message on our channel.
+        return;
+    }
+    string chan_str = llDeleteSubString(message, 0, llStringLength(REQUEST_INVENTORY_PREFIX) - 1);
+    integer new_update_channel = (integer)chan_str;    
+    if (llGetListLength(active_clients) >= MAXIMUM_ACTIVE_CLIENTS) {
+        // got to tell them "not right now".  we'll pretend we have no
+        // scripts; they'll know what we mean if the update client is
+        // recent enough.  really old clients will just go to sleep until later.
+        if (DEBUGGING) log_it("having to disallow new client '" + llKey2Name(id) + "', too many now.");
+        llSay(new_update_channel, REPORT_AVAILABLE_SCRIPTS + BUSY_BUSY);
+        return;
+    }
+
+    // looks like we're going to try to handle the request for them.    
+    if (DEBUGGING) log_it("server heard update req on chan " + (string)channel + " from: " + llKey2Name(id));
+    
+//log_it("add client convo chan " + (string)new_update_channel);
+    integer existing_indy = find_in_list(active_clients, id);
+    if (existing_indy < 0) {
+        active_clients += id;
+        active_update_channels += new_update_channel;
+        integer new_listen_id = llListen(new_update_channel, "", id, "");
+//log_it("add listen " + (string)new_listen_id + " on chan " + (string)new_update_channel);
+        active_listen_ids += new_listen_id;
+        active_timestamps += llGetUnixTime();
+        set_our_label();
+    } else {
+//        if (DEBUGGING) log_it("same client came back before finishing previous upgrade, rolling with it.");
+        // delete old listener so we don't leave it dangling.
+        integer old_listen_id = llList2Integer(active_listen_ids, existing_indy);
+//log_it("remove old listen " + (string)old_listen_id);
+        llListenRemove(old_listen_id);
+        // update the channel and listener id for the new registration.
+        active_update_channels = chop_list(active_update_channels, 0, existing_indy - 1)
+            + [ new_update_channel ]
+            + chop_list(active_update_channels, existing_indy + 1,
+                llGetListLength(active_update_channels) - 1);
+        integer new_listen_id = llListen(new_update_channel, "", id, "");
+//log_it("add new listen " + (string)new_listen_id);
+        active_listen_ids = chop_list(active_listen_ids, 0, existing_indy - 1)
+            + [ new_listen_id ]
+            + chop_list(active_listen_ids, existing_indy + 1,
+                llGetListLength(active_listen_ids) - 1);
+        active_timestamps = chop_list(active_timestamps, 0, existing_indy - 1)
+            + [ new_listen_id ]
+            + chop_list(active_timestamps, existing_indy + 1,
+                llGetListLength(active_timestamps) - 1);
+    }
+
+    // our report name is always called available scripts, but it can actually have
+    // script dependency definitions, script names and object names.
+    string msg = REPORT_AVAILABLE_SCRIPTS;
+    string curr;  // temp.
+
+    // add in the huff updater, since that's the most crucial that they know we have.
+    integer posn;
+    string UPDATE_CLIENT_SCRIPT = "huff-update client";
+    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
+        curr = llList2String(scripts_available, posn);
+        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
+                == UPDATE_CLIENT_SCRIPT) {
+//log_it("found "  + curr);
+            msg += curr + UPDATER_PARM_SEPARATOR;
+            posn = 99999;  // jump out.
+        }
+        if (DEBUGGING && (posn == llGetListLength(scripts_available) - 1) ) {
+            log_it("epic fail, found no updater client script.");
+        }
+    }
+
+    // speak about the dependencies that we know.
+    for (posn = 0; posn < llGetListLength(known_script_dependencies); posn++) {
+        msg += SCRIPT_DEPENDENCY_MARK
+            + llList2String(known_script_dependencies, posn) + UPDATER_PARM_SEPARATOR;
+        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+            msg = REPORT_AVAILABLE_SCRIPTS;
+        }
+    }        
+    // tell this new client what scripts we have.
+    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
+        curr = llList2String(scripts_available, posn);
+        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
+                != UPDATE_CLIENT_SCRIPT) {            
+            // add in the next item, along with the parameter separator.
+            msg += curr + UPDATER_PARM_SEPARATOR;
+//log_it("adding " + curr);
+            if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+                llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+                if (channel == OLD_REQUEST_INVENTORY_CHANNEL) {
+                    // stop sending the list to them since they may not know how
+                    // to interpret a multiple part update list.
+                    return;
+                }
+                llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+                msg = REPORT_AVAILABLE_SCRIPTS;
+            }
+        }
+    }
+    // mention any objects that are available.
+    for (posn = 0; posn < llGetListLength(objects_available); posn++) {
+        // add in the next item, along with the parameter separator.            
+        msg += llList2String(objects_available, posn)
+            + UPDATER_PARM_SEPARATOR;
+        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
+            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
+//log_it(msg + CONTINUANCE_MARKER);
+            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
+            msg = REPORT_AVAILABLE_SCRIPTS;
+        }
+    }
+    // say final bit, even if it's mostly blank.  we need to let them know
+    // that we're done and not adding that continuation flag string.
+    llSay(new_update_channel, msg);
+}
+
+// handles verbal commands from objects that want updates.
+process_verbal_requests(integer channel, string name, key id, string message)
+{
+    if ( (channel == OLD_REQUEST_INVENTORY_CHANNEL) || (channel == inventory_request_channel) ) {
+        spew_inventory_list(channel, message, id);
+        return;
+    } else if (channel == USER_COMMAND_CHANNEL) {
+if (DEBUGGING) log_it("heard orders: " + message);
+        // simple verbal commands.
+        if (message == RESTART_UPDATER_COMMAND) {
+            log_it("Restarting now.");
+            llResetScript();
+        } else if (message == SHOW_SCRIPTS_COMMAND) {
+            show_scripts();
+        } else if (message == SHUTDOWN_COMMAND) {
+            // we will de-rez now (i.e., die) if we are not one of the special names that is undying.
+            if (!matches_substring(llGetObjectName(), "keeper")) {
+//                log_it("server " + (string)inventory_request_channel + " now disintegrating.");
+                squonk(1);
+                llDie();
+            }
+        }
+        return;
+    }
+
+    integer indy;
+    // see if the channel is for one of our valid updates that's in progress.
+    for (indy = 0; indy < llGetListLength(active_update_channels); indy++) {
+        integer cur_chan = llList2Integer(active_update_channels, indy);
+        if (cur_chan == channel) {
+            // yes, this is really for that guy.
+            propel_upgrade_process(channel, id, message);
+            return;
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+//    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// a random channel for the first interaction with the client.
+integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+    
+    if (IS_OPENSIM && (llGetListLength(removal_list) > 0) ) {
+        log_it("now restarting to avoid opensim late updating change event.");
+        llResetScript();
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+    // thirdly, try to clean out the notecards.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.4.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+default
+{
+    state_entry()
+    {
+        auto_retire();
+        initialize_root();  // get set up to start answering requests.
+        llWhisper(0, llGetScriptName() + " started...  touch for more info.");
+        squonk(0);
+    }
+    
+    state_exit() { llSetTimerEvent(0); }
+
+    on_rez(integer parm) {
+        state rerun;
+    }
+
+    timer() { handle_timer(); }
+
+    touch_start(integer count) {
+        show_status(llDetectedKey(0));
+    }
+    
+    listen(integer channel, string name, key id, string message) {
+        // make sure that the object is something we should even talk to.
+        if (llGetOwnerKey(id) != llGetOwner()) {
+            return;
+        }
+        // looks okay, let's see if this is useful communication.
+        process_verbal_requests(channel, name, id, message); 
+    }
+
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            log_it("inventory changed, scheduled a restart.");
+            // sleep a little bit; otherwise we get SL noise about scripts not being
+            // there when it told us they were there.  this can lead to some scripts
+            // doing bizarre things if they are running when added.
+            dealing_with_change = TRUE;
+            llSetTimerEvent(0.0);  // kludge to get around second life bug.
+            llSetTimerEvent(CHANGED_INVENTORY_SNOOZER);
+        }
+    }
+}
+
+state rerun { state_entry() { state default; } }
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/a_huffotronic_update_server_v23.2.txt b/huffware/huffotronic_updater_freebie_v5.3/a_huffotronic_update_server_v23.2.txt
deleted file mode 100755 (executable)
index ef201cf..0000000
+++ /dev/null
@@ -1,940 +0,0 @@
-
-// huffware script: huff-update server, by fred huffhines.
-//
-// this script is the server side of the update process.  it should reside in an object that
-// has all the newest versions of scripts and objects that will be updated.  when rezzed, and
-// at periodic intervals, it announces on a private chat channel that updates are available.
-// when objects respond that they might like an update, it tells them the scripts that it has
-// stored inside of it.  if any of those scripts are an older version inside the client
-// (update requesting) object, then the client will request the newer versions.  the server
-// object will stuff them into it and tell them to start running.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer IS_OPENSIM = TRUE;  // must be set to true for opensim, false for second life.
-
-integer DEBUGGING = FALSE;  // set this to true for noisier diagnostics.
-
-
-
-// updater dependency section:
-// should be moved to a notecard!!!
-//
-// format is a list of strings, where each string has a pair wrapped by the
-// huffware item separators.  the pair contains (1) the basename of a script
-// that has a new dependency and (2) the basename of that new dependency.
-list known_script_dependencies;
-
-
-
-
-load_script_deps()
-{
-    known_script_dependencies = [
-        llDumpList2String(["jaunt wik rez", "jaunt config funcs"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["jaunt wik rez", "data cow"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["jaunt wik rez", "jaunt rezolator"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["remotely personable", "inventory exchanger"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "exchange driver hudimation"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "avatar timer manager"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["animote main driver", "avatar choice memory"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["giftorse", "particle projector"], ITEM_LIST_SEPARATOR),
-        llDumpList2String(["huff-search brainiac", "searchbert armature"], ITEM_LIST_SEPARATOR),
-
-        
-//special purpose -- removes the updater from the elevator buttons...
-//llDumpList2String(["comfortable sitting", "zap updater from elevators"], ITEM_LIST_SEPARATOR),
-// => do not uncomment unless you want your elevators to shed their ability to update.
-
-
-        // this allows us to add or remove items above at will without complaints about comma.
-        llDumpList2String(["xyzzy", "hopefully-never-matches"], ITEM_LIST_SEPARATOR)
-    ];
-}
-
-
-
-
-// global constants...
-
-integer USER_COMMAND_CHANNEL = 4;  // channel where we listen to user commands.
-
-float ANNOUNCEMENT_PERIOD = 14.0;  // how often we tell other objects that we have tasty treats.
-
-integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
-integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
-
-string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
-string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
-string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
-string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
-string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
-string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
-string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
-string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
-string DONE_UPDATING                = "#finito#";  // the client is done updating.
-string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
-
-integer UPDATER_SCRIPT_PIN          = -1231008;  // the hook for our scripts to be modified.
-
-string RESTART_UPDATER_COMMAND      = "#restart";  // said in open chat to recrank the updater.
-string SHOW_SCRIPTS_COMMAND         = "#show";  // said in open chat to list out the scripts.
-string SHUTDOWN_COMMAND             = "#destroy";  // shuts down object and destroys it.
-
-string UPDATER_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-
-string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
-
-integer ENTRIES_PER_LINE = 4;  // number of items from a list shown on one line of text.
-
-integer MAXIMUM_ACTIVE_CLIENTS = 5;  // number of conversations we will allow at a time.
-
-float LONGEST_SLACK_PER_CLIENT = 84.0;
-    // we allow a client to be out of touch with us for this many seconds.  after that,
-    // we decide it's deceased and remove it from our list.
-
-integer MESSAGE_SIZE_LIMIT = 800;  // longest thing that can be safely said without clipping (guess).
-
-float SCRIPT_LIST_PAUSE_INTERVAL = 1.4;  // pause between large chunks of update text.
-
-string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
-
-float CHANGED_INVENTORY_SNOOZER = 7.0;
-    // the number of seconds we sleep once we see an inventory change.  we don't want to
-    // react to this immediately.  this overrides the normal announcement cycle until it's
-    // dealt with by the timer.
-
-string CONTINUANCE_MARKER = "...";
-    // a string sent when the update list is too long and needs to be continued in another chat.
-
-string UPDATER_BASE_NAME = "huff-update client";
-    // the name of the updater script that keeps everything in sync.
-
-//////////////
-
-// global variables...
-
-list scripts_available;  // the list of scripts we have in our inventory for distribution.
-list objects_available;  // list of objects for handing out.
-
-list active_clients;  // list of keys for clients that are updating currently.
-list active_update_channels;  // active conversations on client chosen channels.
-list active_listen_ids;  // the ids for the listener on those channels.
-list active_timestamps;  // tracks when the client was last active.
-
-integer inventory_request_channel;  // our personal channel that the update client should talk with.
-
-integer dealing_with_change;  // has the inventory changed?  we will deal with this in the timer.
-
-// displays the status of the update server.
-show_status(key who_says)
-{
-    string title = "[mem free=" + (string)llGetFreeMemory() + "]";
-    title = "Listening for requests on channel " + (string)inventory_request_channel;
-    if (llGetListLength(active_update_channels))
-        title += "\nactive channels="
-            + dump_list(active_update_channels, FALSE, ENTRIES_PER_LINE);
-    else
-        title += "\nNo channels active.";
-        
-    if (llGetListLength(active_clients))
-        title += "\nactive clients=" + dump_keyed_list(active_clients, TRUE, 2);
-    else
-        title += "\nNo clients active.";
-    
-    if (llGetOwner() == who_says) {
-        string addition = " ";
-        if (USER_COMMAND_CHANNEL != 0) addition = "/" + (string)USER_COMMAND_CHANNEL + " ";
-        title += "\n[ \"" + addition + SHOW_SCRIPTS_COMMAND + "\" lists all the scripts, "
-            + "\"" + addition + SHUTDOWN_COMMAND + "\" zaps the updater, "
-            + "\"" + addition + RESTART_UPDATER_COMMAND + "\" refreshes the updater ]";
-    }
-
-    llWhisper(0, title);
-}
-
-// plink a quietous string of resonance...
-squonk(integer indy)
-{
-    string snd = llGetInventoryName(INVENTORY_SOUND, indy);
-    if (snd != "") llTriggerSound(snd, 1.0);
-}
-
-// list out the scripts that the server's object contains.
-show_scripts()
-{
-    string title = (string)llGetListLength(scripts_available) + " scripts available:";
-    show_list(title, scripts_available);
-    title = (string)llGetListLength(objects_available) + " objects available:";
-    show_list(title, objects_available);
-}
-
-// lets the client know that we're here and have some scripts available.
-announce_presence()
-{
-    if (llGetListLength(active_clients) < MAXIMUM_ACTIVE_CLIENTS) {
-        // only announce if we're not already booked up.
-        llWhisper(UPDATE_ANNOUNCEMENT_CHANNEL, UPDATE_ANNOUNCEMENT_PREFIX + (string)inventory_request_channel);
-    }
-}
-
-// lifted from "clear text and effects" script; should be nearly identical
-// to that, except that we set the texture animation.
-reset_all_effects()
-{
-    llSetText("", <0,0,0>, 0);  // clear any text above object.
-    llSetSitText("Sit Here");  // reset sit text to default state.
-    llSetTouchText("Touch");  // similarly for touch.
-    llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
-    llParticleSystem([]);  // turn off all particles.
-    llSensorRemove();  // stop any running sensors.
-    llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
-    llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
-    // keep it from being physical and from disapparating.
-    llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE,
-        PRIM_PHANTOM, TRUE]);
-    llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
-
-    //
-    // the following are specific to the huffotronic update server.
-    //
-
-    // we re-assert our special texture set here, in case some wayward scripts have
-    // messed with us.
-    integer textures_held = llGetInventoryNumber(INVENTORY_TEXTURE);
-    integer indy;
-    for (indy = 0; indy < textures_held; indy++) {
-        string curr_tex = llGetInventoryName(INVENTORY_TEXTURE, indy);
-        // we have a simple scheme for putting textures on the updater.
-        // we have an inside, an outside and the ends.
-        if (is_prefix(curr_tex, "~~s0")) {
-            llSetTexture(curr_tex, ALL_SIDES);
-        } else if (is_prefix(curr_tex, "~~s1")) {
-            llSetTexture(curr_tex, 1);
-        } else if (is_prefix(curr_tex, "~~s2")) {
-            llSetTexture(curr_tex, 0);
-            llSetTexture(curr_tex, 3);
-        }
-    }
-    
-    // re-assert our texture animation also.
-    llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE,
-        ALL_SIDES, 0, 0, 0, TWO_PI, 1.0 / 36.0);
-}
-
-// set up the update server object.
-initialize_root()
-{
-    // set up our particular "look".
-    reset_all_effects();
-
-    // shut down any competing scripts in this object.
-    // we try to swat any other script that's been added before we let them do weird
-    // stuff.  for example, a pet script might start acting like one.  this
-    // function is not guaranteed to run before that bad stuff can happen,
-    // and that's maybe the one major issue with this approach.  as long as
-    // the contained scripts aren't evil (like if they jump someplace else
-    // as soon as they start), then there shouldn't be any serious problems.
-    knock_down_other_scripts();
-
-    // reset our variables.
-    active_update_channels = [];
-    active_listen_ids = [];
-    active_clients = [];
-    active_timestamps = [];
-    scripts_available = [];
-    objects_available = [];
-    dealing_with_change = FALSE;  // not handling any inventory changes.
-
-    // make sure we know about any scripts that have new dependencies.
-    load_script_deps();
-
-    // clean out any older versions of the scripts before we make our
-    // inventory.
-    destroy_older_versions();
-
-    // now accumulate the list of scripts in our inventory.    
-    integer items_held = llGetInventoryNumber(INVENTORY_SCRIPT);
-    integer indy;
-    for (indy = 0; indy < items_held; indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        // we don't provide our own script for updating; it must be kept from
-        // floating around, like into other objects that are not updaters.
-////        if (curr_script != llGetScriptName())
-            scripts_available += curr_script;
-    }
-    items_held = llGetInventoryNumber(INVENTORY_OBJECT);
-    for (indy = 0; indy < items_held; indy++) {
-        objects_available += llGetInventoryName(INVENTORY_OBJECT, indy);
-//log_it("added obj: " + llGetInventoryName(INVENTORY_OBJECT, indy));
-    }
-    items_held = llGetInventoryNumber(INVENTORY_NOTECARD);
-    for (indy = 0; indy < items_held; indy++) {
-        objects_available += llGetInventoryName(INVENTORY_NOTECARD, indy);
-//log_it("added note: " + llGetInventoryName(INVENTORY_NOTECARD, indy));
-    }
-
-    // listen to the owner.
-    llListen(USER_COMMAND_CHANNEL, "", llGetOwner(), "");
-    // listen for any requests from our loyal clients.
-    inventory_request_channel = random_channel();
-    llListen(inventory_request_channel, "", NULL_KEY, "");
-    // listen for older clients too.
-    llListen(OLD_REQUEST_INVENTORY_CHANNEL, "", NULL_KEY, "");
-
-    // set up the periodic announcements.
-    llSetTimerEvent(ANNOUNCEMENT_PERIOD);
-}
-
-handle_timer()
-{
-    if (dealing_with_change) {
-        dealing_with_change = FALSE;
-        state rerun;  // zoom back to the starting point.
-    }
-    integer indy;
-    integer timecheck = llGetUnixTime();  // use for whole loop.
-    for (indy = llGetListLength(active_timestamps) - 1; indy >= 0; indy--) {
-        integer last_time = llList2Integer(active_timestamps, indy);
-        if (llAbs(last_time - timecheck) > LONGEST_SLACK_PER_CLIENT) {
-            // we need to clear out this item.  we know we can whack the client
-            // at the same index and that will take care of this slacker.
-            key curr_key = llList2Key(active_clients, indy);
-            log_it("timed-out client: " + llKey2Name(curr_key) + " [" + (string)curr_key + "]");
-            remove_client(curr_key);
-        }
-    }
-
-    // let the objects nearby know that we are open for business by
-    // announcing the script inventory.
-    announce_presence();
-}
-
-// turns a list into a nicely formatted string.
-string dump_list(list to_show, integer initial_line_break, integer entries_per_line)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we break every Nth entry, but not if it's the first line and
-        // they said to not have the initial line break.
-        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
-            msg += "\n";
-        string cursc = llList2String(to_show, indy);
-        msg += cursc;
-        // add commas where needed.
-        if (indy < llGetListLength(to_show) - 1)
-            msg += ", ";
-    }
-    return msg;
-}
-
-// similar to dump_keyed_list, but only shows the names, each on their own line.
-string dump_names_for_keys(list to_show)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we only line break after the first entry.
-        if (indy > 0) msg += "\n";
-        string keystr = llList2String(to_show, indy);
-        msg += llKey2Name(keystr);
-    }
-    return msg;
-}
-
-// similar to dump_list
-string dump_keyed_list(list to_show, integer initial_line_break, integer entries_per_line)
-{
-    string msg;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(to_show); indy++) {
-        // we break every Nth entry, but not if it's the first line and
-        // they said to not have the initial line break.
-        if ( !(indy % entries_per_line) && (indy || initial_line_break) )
-            msg += "\n";
-        string keystr = llList2String(to_show, indy);
-        msg += llKey2Name(keystr) + " (" + keystr + ")";
-        // add commas where needed.
-        if (indy < llGetListLength(to_show) - 1)
-            msg += ", ";
-    }
-    return msg;
-}
-
-// shows the list specified in a compact manner.
-show_list(string title, list to_show)
-{
-    string to_say = title + dump_list(to_show, TRUE, ENTRIES_PER_LINE);
-    // flush some memory.
-    title = "";
-    to_show = [];
-    integer indy;
-    // say the output in pieces to avoid over-clogging chat.
-    for (indy = 0; indy < llStringLength(to_say); indy += MESSAGE_SIZE_LIMIT) {
-        integer last_indy = indy + MESSAGE_SIZE_LIMIT - 1;
-        string addition;
-        if (last_indy < llStringLength(to_say)) addition = CONTINUANCE_MARKER;
-        llWhisper(0, llGetSubString(to_say, indy, last_indy) + addition);
-    }
-}
-
-// stops all the scripts besides this one.
-knock_down_other_scripts()
-{
-    // set all scripts but this to not be running.
-    integer indy;
-    string self_script = llGetScriptName();
-    list split = compute_basename_and_version(self_script);
-    string self_base = llList2String(split, 0);
-    self_script = ""; split = [];  // free memory.
-    integer count = llGetInventoryNumber(INVENTORY_SCRIPT);
-    // we set all other scripts that are not versions of this script to not be running.
-    for (indy = 0; indy < count; indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if (!is_prefix(curr_script, self_base)
-            && !is_prefix(curr_script, UPDATER_BASE_NAME) ) {
-            llSetScriptState(curr_script, FALSE);
-        }
-    }
-}
-
-// set a text label on the updater with the list of clients.
-set_our_label()
-{
-    string label = "";
-    if (llGetListLength(active_clients) > 0) label = "[updating]\n";
-    llSetText(label + dump_names_for_keys(active_clients), <0.8, 0.95, 0.92>, 1.0);
-}
-
-// clean out a client that we should be done with.
-remove_client(key id)
-{
-    // locate said client of deceased nature...
-    integer indy = find_in_list(active_clients, id);
-    if (indy < 0) {
-//        if (DEBUGGING) log_it("failure to find client to remove: " + (string)id);
-        return;
-    }
-    active_clients = llDeleteSubList(active_clients, indy, indy);
-    // also clean out the channel and stop listening to it.
-integer act_chan = llList2Integer(active_update_channels, indy);
-    active_update_channels = llDeleteSubList(active_update_channels, indy, indy);
-    integer listen_to_remove = llList2Integer(active_listen_ids, indy);
-//log_it("remove listen " + (string)listen_to_remove + " on chan " + (string)act_chan);
-    llListenRemove(listen_to_remove);
-    active_listen_ids = llDeleteSubList(active_listen_ids, indy, indy);
-    active_timestamps = llDeleteSubList(active_timestamps, indy, indy);
-    set_our_label();
-}
-
-// fix a partial match to a script name if we can't find the exact item.
-string backpatch_script_name(string partial)
-{
-    if (llGetInventoryType(partial) == INVENTORY_SCRIPT) return partial;  // all set.
-    integer dep_indy;
-    for (dep_indy = 0; dep_indy < llGetInventoryNumber(INVENTORY_SCRIPT); dep_indy++) {
-        string curr_name = llGetInventoryName(INVENTORY_SCRIPT, dep_indy);
-        if (is_prefix(curr_name, partial)) {
-//            log_it("found real name " + curr_name + " for part: " + partial);
-            return curr_name;
-        }
-    }
-//    log_it("no matches for partial script name!");
-    return "";  // no matches!
-}
-
-// moves the upgrade process with "id" along to the next step given the request in
-// the message.
-propel_upgrade_process(integer channel, key id, string message)
-{
-    if (DEBUGGING) log_it("got upgrade note from " + (string)id + " with msg=" + message);
-    if (message == REQUEST_SCRIPT_UPDATE) {
-        // begins the update process with the client.
-        llSay(channel, SHUT_THEM_DOWN);
-    } else if (is_prefix(message, READY_TO_UPDATE)) {
-        // whack the prefix so we can get the list they want.
-        message = llDeleteSubString(message, 0, llStringLength(READY_TO_UPDATE) - 1);
-        list requests = llParseString2List(message, [UPDATER_PARM_SEPARATOR], []);
-        message = "";
-        // send over the scripts the client asked for, since it seems to be ready for them.
-        if (llGetListLength(requests)) {
-            show_list("updating " + llKey2Name(id) + " (key " + (string)id + ") with", requests);
-            integer indy;
-            for (indy = 0; indy < llGetListLength(requests); indy++) {
-                string curr = llList2String(requests, indy);
-                if (find_in_list(objects_available, curr) >= 0) {
-//log_it("handing object over: " + curr);
-                    // it's an object, so treat it that way.
-                    llGiveInventory(id, curr);
-                } else {
-//log_it("handing script over: " + curr);
-                    // assume it's a script, and use script pin to stuff it.
-                    curr = backpatch_script_name(curr);
-                    if (curr != "") {
-//                        integer starting_state = FALSE;
-// second life was okay with scripts being plugged in unstarted.  opensim is not.
-// and second life appears to be unhappy with scripts plugged in as started.  so we
-// have an impasse.
-// this should be: true for opensim, and false for second life.
-                        integer starting_state = IS_OPENSIM;
-//                        if (DEBUGGING) log_it("installing script using updater pin.");
-                        llRemoteLoadScriptPin(id, curr, UPDATER_SCRIPT_PIN, starting_state, 0);
-                    }
-                }
-            }
-        }
-    } else if (message == SCRIPTS_ARE_CURRENT) {
-        // the client thinks it's ready to get back up and running.
-//log_it("heard client is ready!");
-        llSay(channel, START_THEM_UP);
-        // kludge for older clients (pre 10.4 version) to try to help them start up.
-//old and not useful.        llSleep(0.2); llSay(channel, START_THEM_UP); llSleep(0.2); llSay(channel, START_THEM_UP);
-        remove_client(id);
-    } else if (message == DONE_UPDATING) {
-        // this client has nothing to do for now.
-//log_it("heard client is done: " + (string)id);
-        remove_client(id);
-    } else {
-//log_it("weird note from client: " + message);
-        return;  // not used.
-    }
-    
-}
-
-// blasts out the inventory list to a curious client.
-spew_inventory_list(integer channel, string message, key id)
-{
-    if (!is_prefix(message, REQUEST_INVENTORY_PREFIX)) {
-
-        // this is an old style update alert that we still use at startup of the client
-        // to ensure that finishing replacement of the updater script is never unnoticed.
-        if (is_prefix(message, DONE_UPDATING)) {
-//            if (DEBUGGING) log_it("found very special message from startup of updater.");
-            propel_upgrade_process(channel, id, message);
-        }
-        
-        // argh, this is not the right kind of message on our channel.
-        return;
-    }
-    string chan_str = llDeleteSubString(message, 0, llStringLength(REQUEST_INVENTORY_PREFIX) - 1);
-    integer new_update_channel = (integer)chan_str;    
-    if (llGetListLength(active_clients) >= MAXIMUM_ACTIVE_CLIENTS) {
-        // got to tell them "not right now".  we'll pretend we have no
-        // scripts; they'll know what we mean if the update client is
-        // recent enough.  really old clients will just go to sleep until later.
-        if (DEBUGGING) log_it("having to disallow new client '" + llKey2Name(id) + "', too many now.");
-        llSay(new_update_channel, REPORT_AVAILABLE_SCRIPTS + BUSY_BUSY);
-        return;
-    }
-
-    // looks like we're going to try to handle the request for them.    
-    if (DEBUGGING) log_it("server heard update req on chan " + (string)channel + " from: " + llKey2Name(id));
-    
-//log_it("add client convo chan " + (string)new_update_channel);
-    integer existing_indy = find_in_list(active_clients, id);
-    if (existing_indy < 0) {
-        active_clients += id;
-        active_update_channels += new_update_channel;
-        integer new_listen_id = llListen(new_update_channel, "", id, "");
-//log_it("add listen " + (string)new_listen_id + " on chan " + (string)new_update_channel);
-        active_listen_ids += new_listen_id;
-        active_timestamps += llGetUnixTime();
-        set_our_label();
-    } else {
-//        if (DEBUGGING) log_it("same client came back before finishing previous upgrade, rolling with it.");
-        // delete old listener so we don't leave it dangling.
-        integer old_listen_id = llList2Integer(active_listen_ids, existing_indy);
-//log_it("remove old listen " + (string)old_listen_id);
-        llListenRemove(old_listen_id);
-        // update the channel and listener id for the new registration.
-        active_update_channels = chop_list(active_update_channels, 0, existing_indy - 1)
-            + [ new_update_channel ]
-            + chop_list(active_update_channels, existing_indy + 1,
-                llGetListLength(active_update_channels) - 1);
-        integer new_listen_id = llListen(new_update_channel, "", id, "");
-//log_it("add new listen " + (string)new_listen_id);
-        active_listen_ids = chop_list(active_listen_ids, 0, existing_indy - 1)
-            + [ new_listen_id ]
-            + chop_list(active_listen_ids, existing_indy + 1,
-                llGetListLength(active_listen_ids) - 1);
-        active_timestamps = chop_list(active_timestamps, 0, existing_indy - 1)
-            + [ new_listen_id ]
-            + chop_list(active_timestamps, existing_indy + 1,
-                llGetListLength(active_timestamps) - 1);
-    }
-
-    // our report name is always called available scripts, but it can actually have
-    // script dependency definitions, script names and object names.
-    string msg = REPORT_AVAILABLE_SCRIPTS;
-    string curr;  // temp.
-
-    // add in the huff updater, since that's the most crucial that they know we have.
-    integer posn;
-    string UPDATE_CLIENT_SCRIPT = "huff-update client";
-    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
-        curr = llList2String(scripts_available, posn);
-        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
-                == UPDATE_CLIENT_SCRIPT) {
-//log_it("found "  + curr);
-            msg += curr + UPDATER_PARM_SEPARATOR;
-            posn = 99999;  // jump out.
-        }
-        if (DEBUGGING && (posn == llGetListLength(scripts_available) - 1) ) {
-            log_it("epic fail, found no updater client script.");
-        }
-    }
-
-    // speak about the dependencies that we know.
-    for (posn = 0; posn < llGetListLength(known_script_dependencies); posn++) {
-        msg += SCRIPT_DEPENDENCY_MARK
-            + llList2String(known_script_dependencies, posn) + UPDATER_PARM_SEPARATOR;
-        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-            msg = REPORT_AVAILABLE_SCRIPTS;
-        }
-    }        
-    // tell this new client what scripts we have.
-    for (posn = 0; posn < llGetListLength(scripts_available); posn++) {
-        curr = llList2String(scripts_available, posn);
-        if (llDeleteSubString(curr, llStringLength(UPDATE_CLIENT_SCRIPT), -1)
-                != UPDATE_CLIENT_SCRIPT) {            
-            // add in the next item, along with the parameter separator.
-            msg += curr + UPDATER_PARM_SEPARATOR;
-//log_it("adding " + curr);
-            if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-                llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-                if (channel == OLD_REQUEST_INVENTORY_CHANNEL) {
-                    // stop sending the list to them since they may not know how
-                    // to interpret a multiple part update list.
-                    return;
-                }
-                llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-                msg = REPORT_AVAILABLE_SCRIPTS;
-            }
-        }
-    }
-    // mention any objects that are available.
-    for (posn = 0; posn < llGetListLength(objects_available); posn++) {
-        // add in the next item, along with the parameter separator.            
-        msg += llList2String(objects_available, posn)
-            + UPDATER_PARM_SEPARATOR;
-        if (llStringLength(msg) > MESSAGE_SIZE_LIMIT - 50) {
-            llSay(new_update_channel, msg + CONTINUANCE_MARKER);
-//log_it(msg + CONTINUANCE_MARKER);
-            llSleep(SCRIPT_LIST_PAUSE_INTERVAL);
-            msg = REPORT_AVAILABLE_SCRIPTS;
-        }
-    }
-    // say final bit, even if it's mostly blank.  we need to let them know
-    // that we're done and not adding that continuation flag string.
-    llSay(new_update_channel, msg);
-}
-
-// handles verbal commands from objects that want updates.
-process_verbal_requests(integer channel, string name, key id, string message)
-{
-    if ( (channel == OLD_REQUEST_INVENTORY_CHANNEL) || (channel == inventory_request_channel) ) {
-        spew_inventory_list(channel, message, id);
-        return;
-    } else if (channel == USER_COMMAND_CHANNEL) {
-if (DEBUGGING) log_it("heard orders: " + message);
-        // simple verbal commands.
-        if (message == RESTART_UPDATER_COMMAND) {
-            log_it("Restarting now.");
-            llResetScript();
-        } else if (message == SHOW_SCRIPTS_COMMAND) {
-            show_scripts();
-        } else if (message == SHUTDOWN_COMMAND) {
-            // we will de-rez now (i.e., die) if we are not one of the special names that is undying.
-            if (!matches_substring(llGetObjectName(), "keeper")) {
-//                log_it("server " + (string)inventory_request_channel + " now disintegrating.");
-                squonk(1);
-                llDie();
-            }
-        }
-        return;
-    }
-
-    integer indy;
-    // see if the channel is for one of our valid updates that's in progress.
-    for (indy = 0; indy < llGetListLength(active_update_channels); indy++) {
-        integer cur_chan = llList2Integer(active_update_channels, indy);
-        if (cur_chan == channel) {
-            // yes, this is really for that guy.
-            propel_upgrade_process(channel, id, message);
-            return;
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-//    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// a random channel for the first interaction with the client.
-integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-    
-    if (IS_OPENSIM && (llGetListLength(removal_list) > 0) ) {
-        log_it("now restarting to avoid opensim late updating change event.");
-        llResetScript();
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-    // thirdly, try to clean out the notecards.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.4.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-default
-{
-    state_entry()
-    {
-        auto_retire();
-        initialize_root();  // get set up to start answering requests.
-        llWhisper(0, llGetScriptName() + " started...  touch for more info.");
-        squonk(0);
-    }
-    
-    state_exit() { llSetTimerEvent(0); }
-
-    on_rez(integer parm) {
-        state rerun;
-    }
-
-    timer() { handle_timer(); }
-
-    touch_start(integer count) {
-        show_status(llDetectedKey(0));
-    }
-    
-    listen(integer channel, string name, key id, string message) {
-        // make sure that the object is something we should even talk to.
-        if (llGetOwnerKey(id) != llGetOwner()) {
-            return;
-        }
-        // looks okay, let's see if this is useful communication.
-        process_verbal_requests(channel, name, id, message); 
-    }
-
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            log_it("inventory changed, scheduled a restart.");
-            // sleep a little bit; otherwise we get SL noise about scripts not being
-            // there when it told us they were there.  this can lead to some scripts
-            // doing bizarre things if they are running when added.
-            dealing_with_change = TRUE;
-            llSetTimerEvent(0.0);  // kludge to get around second life bug.
-            llSetTimerEvent(CHANGED_INVENTORY_SNOOZER);
-        }
-    }
-}
-
-state rerun { state_entry() { state default; } }
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/auto-retire_v2.8.lsl b/huffware/huffotronic_updater_freebie_v5.3/auto-retire_v2.8.lsl
new file mode 100755 (executable)
index 0000000..9c96028
--- /dev/null
@@ -0,0 +1,111 @@
+
+//////////////[copy starting here...]//////////////
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+//////////////[end of area to copy]//////////////
+
+//////////////
+// this is how a user of the auto_retire script gets the retirement process
+// to work.  whenever the script goes into its default state, such as when dropped
+// into an object, this function invocation makes sure that no earlier versions
+// of our script are left in inventory.
+default
+{
+    state_entry() {
+        auto_retire();
+    }
+}
+//////////////
diff --git a/huffware/huffotronic_updater_freebie_v5.3/auto-retire_v2.8.txt b/huffware/huffotronic_updater_freebie_v5.3/auto-retire_v2.8.txt
deleted file mode 100755 (executable)
index 9c96028..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-
-//////////////[copy starting here...]//////////////
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-//////////////[end of area to copy]//////////////
-
-//////////////
-// this is how a user of the auto_retire script gets the retirement process
-// to work.  whenever the script goes into its default state, such as when dropped
-// into an object, this function invocation makes sure that no earlier versions
-// of our script are left in inventory.
-default
-{
-    state_entry() {
-        auto_retire();
-    }
-}
-//////////////
diff --git a/huffware/huffotronic_updater_freebie_v5.3/card_configurator_v8.1.lsl b/huffware/huffotronic_updater_freebie_v5.3/card_configurator_v8.1.lsl
new file mode 100755 (executable)
index 0000000..9653ec0
--- /dev/null
@@ -0,0 +1,499 @@
+
+// huffware script: card configurator, by fred huffhines.
+//
+// processes a notecard with configuration info, then sends the information as packages of
+// configuration nuggest to a consuming script.  this is one level above the noteworthy script,
+// which simply reads the notecard.  this script keeps the config parsing out of higher-level
+// scripts.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+integer MAXIMUM_ITEMS_PER_BURST = 6;
+    // try this out as a good limit for the size of the sends.
+
+// global variables...
+
+string signature_required;
+    // sent to us when the request for configuration info is made.
+
+list good_prefixes;
+    // similarly, a set of prefixes for notecard lines that the calling script
+    // cares about.  if this is empty, then anything will match.
+
+string global_notecard_name;  // name of our notecard in the object's inventory.
+integer response_code;  // set to uniquely identify the notecard read in progress.
+list global_config_list;  // a collection of configuration parameters from our notecard.
+list global_responses;  // the items we want to send back to the requestor.
+
+// card configurator link message API:
+//////////////
+// do not redefine these constants.
+integer CARD_CONFIGURATOR_HUFFWARE_ID = 10042;
+    // the unique id within the huffware system for the card configurator script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+string BAD_NOTECARD_TEXT = "*badcrd*";
+    // the sign that we hated the notecards we found, or there were none.
+string FINISHED_READING_NOTECARDS = "**finished**";
+    // the sign that we are done plowing through the card we found.
+string BEGIN_READING_NOTECARD_COMMAND = "#read-cfg#";
+    // requests that the configurator find a good notecard and read its contents.
+    // it should send the contents via the alert below.  first parm is the signature and
+    // second is the wrapped list of valid item prefixes.
+string READ_PARTICULAR_NOTECARD_COMMAND = "#read-note#";
+    // requests that the configurator find a good notecard and read its contents.
+    // it should send the contents via the alert below.  first two parms are the same as
+    // begin reading notecard, and the third parameter is the name of the specific notecard.
+string CARD_CONFIG_RECEIVED_ALERT = "#cfg-event-upd#";
+    // this message is sent when the configurator has found some data updates or has finished
+    // reading the configuration file.
+//////////////
+
+// imported interfaces below...
+
+// requires noteworthy library v8.5 or better.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+// commands available via the noteworthy library:
+string BUSY_READING_INDICATOR = "busy_already";
+    // this return value indicates that the script is already in use by some other script.
+    // the calling script should try again later.
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be blank.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
+    // found) and as subsequent elements an embedded list that was read from the
+    // notecard.  this necessarily limits the size of the notecards that we can read
+    // and return.
+string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
+    // like the read notecard command, but specifies the notecard name to use.  only that
+    // specific notecard file will be consulted.  first and second parm are still signature
+    // and response code, third parm is the notecard name.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// this function fires off a request to the noteworthy library via a link message.
+// noteworthy will look for a notecard with our particular signature in it and
+// if it finds one, it will read the configuration therein.  an empty string is
+// returned if noteworthy couldn't find anything.
+request_configuration()
+{
+    global_notecard_name = "";  // reset any previous card.
+    // try to find a notecard with our configuration.
+    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([signature_required, response_code]);
+    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+         parms_sent);
+}
+
+request_specific_configuration()
+{
+    // try to find a notecard with our configuration.
+    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([signature_required, response_code, global_notecard_name]);
+    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_SPECIFIC_NOTECARD_COMMAND,
+         parms_sent);
+}
+
+// processes link messages received from the noteworthy library.
+process_notecard(integer which, integer num, string msg, key id)
+{
+    if (msg != READ_NOTECARD_COMMAND) return;  // not for us.
+    // process the result of reading the notecard.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string notecard_name = llList2String(parms, 0);
+    integer response_for = llList2Integer(parms, 1);
+    if (response_for != response_code) return;  // oops, this isn't for us.
+    if (notecard_name != BAD_NOTECARD_TEXT) {
+        // a valid notecard has been found.
+        global_notecard_name = notecard_name;  // record its name for later use.
+        // snag all but the first two elements for our config now.
+        global_config_list = llList2List(parms, 2, -1);
+        parms = [];  // toss the old copy.
+        // and process the file as a set of definitions.
+        process_ini_config();
+        send_data_burst();  // send any pending configs out.
+        if (notecard_name != NOTECARD_READ_CONTINUATION) {
+//log_it("sending final sentinel at end of card.");
+            // blast out a fake data burst that means we're done reading.
+            global_notecard_name = FINISHED_READING_NOTECARDS;
+            global_responses += [ FINISHED_READING_NOTECARDS ];
+            send_data_burst();
+        }
+//log_it("after config read, memory left=" + (string)llGetFreeMemory());
+    } else {
+        // we hated the notecards we found, or there were none.
+        // send a failure response.
+        llMessageLinked(LINK_THIS, CARD_CONFIGURATOR_HUFFWARE_ID + REPLY_DISTANCE,
+            CARD_CONFIG_RECEIVED_ALERT, wrap_parameters([BAD_NOTECARD_TEXT]));
+    }
+}
+
+///////////////
+
+// sends the currently held data out to whoever requested it.
+send_data_burst()
+{
+    if (!llGetListLength(global_responses)) return;  // nothing to send.
+//log_it("sending " + (string)llGetListLength(global_responses) + " items");
+    llMessageLinked(LINK_THIS, CARD_CONFIGURATOR_HUFFWARE_ID + REPLY_DISTANCE, CARD_CONFIG_RECEIVED_ALERT,
+        wrap_parameters([global_notecard_name] + global_responses));
+    global_responses = [];  // reset any items held.
+}
+
+// consumes the notecard in a very application specific way to retrieve our configuration items.
+// the example script only looks for two variables: name and description.  if those are found in
+// the sample card, then they are proudly shown.
+parse_variable_definition(string to_parse)
+{
+    string content;  // filled after finding a variable name.
+    list x_y = separate_variable_definition(to_parse);
+    string x = llList2String(x_y, 0);
+    if (!llGetListLength(good_prefixes)) {
+        global_responses += x_y;
+    } else {
+        integer indy;
+        for (indy = 0; indy < llGetListLength(good_prefixes); indy++) {
+            // if it's one of our desired prefixes, then we add it.
+            if (is_prefix(x, llList2String(good_prefixes, indy))) {
+                global_responses += x_y;
+                indy = llGetListLength(good_prefixes) + 5;  // skip rest of loop.
+            }
+        }
+    }
+    
+    if (llGetListLength(global_responses) > MAXIMUM_ITEMS_PER_BURST) {
+        send_data_burst();
+    }
+}
+
+// examines all entries that we got from the notecard to see if any contain definitions.
+// this is basically an INI file reader, but it uses a list instead of a file.
+// ini files provide a format with multiple sections of config information, like so:
+//    [section_1]
+//    name1=value1
+//    name2=value2 ...etc...
+//    [section_2]
+//    name1=value1 ...etc...
+process_ini_config()
+{
+//    log_it("scanning notecard for variable definitions...");
+    integer indy;
+    integer count = llGetListLength(global_config_list);
+    // iterate across the items in our configuration to look for ones that are not done yet.
+    for (indy = 0; indy < count; indy++) {
+        string line = llList2String(global_config_list, indy);
+//log_it("ini proc: " + line);
+        // search for a section beginning.
+        if (llGetSubString(line, 0, 0) == "[") {
+            // we found the start of a section name.  now read the contents.
+//            log_it("reading section: " + llGetSubString(line, 1, -2));
+//            global_responses += [ line, "e" ];
+            indy++;  // skip the section line.
+        }
+        integer sec_indy;
+        for (sec_indy = indy; sec_indy < count; sec_indy++) {
+            // read the lines in the section.
+            line = llList2String(global_config_list, sec_indy);
+            if (llGetSubString(line, 0, 0) != "[") {
+                // try to interpret this line as a variable setting.  this is just
+                // one example of a way to handle the config file; one might instead
+                // want to do something below once a whole section is read.
+                parse_variable_definition(line);
+            } else {
+                // we're at the beginning of a new section now, so start processing its
+                // configuration in the outer loop.
+                indy = sec_indy - 1;  // set indy to proper beginning of section.
+                sec_indy = count + 3;  // skip remainder of inner loop.
+            }
+        }
+        if (sec_indy == count) indy = count + 3;  // skip out of loop now.
+    }
+    global_config_list = [];  // we ate it!
+}
+
+initialize_specific(string specific_card)
+{
+    // reset our relevant variables.
+    global_notecard_name = specific_card;
+    global_config_list = [];
+    global_responses = [];
+
+    // request that the noteworthy library start looking for our notecard.
+    request_specific_configuration();
+}
+
+initialize()
+{
+    // reset our relevant variables.
+    global_notecard_name = "";
+    global_config_list = [];
+    global_responses = [];
+
+    // request that the noteworthy library start looking for our notecard.
+    request_configuration();
+}
+
+//////////////
+// from hufflets...
+//
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+integer find_substring(string full_string, string pattern)
+{
+    string full_lower = llToLower(full_string);
+    return llSubStringIndex(full_lower, pattern);
+}
+
+//////////////
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// strips the spaces off of the beginning and end of a string.
+string strip_spaces(string to_strip)
+{
+    // clean out initial spaces.
+    while (llGetSubString(to_strip, 0, 0) == " ")
+        to_strip = llDeleteSubString(to_strip, 0, 0);
+    // clean out ending spaces.
+    while (llGetSubString(to_strip, -1, -1) == " ")
+        to_strip = llDeleteSubString(to_strip, -1, -1);
+    return to_strip;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+///log_it("got x = " + x + " and y = " + y);
+    return [ strip_spaces(x), strip_spaces(y) ];
+}
+//
+// end hufflets
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();  // make sure newest addition is only version of script.
+    }
+
+    on_rez(integer parm) { state rerun; }
+
+    link_message(integer sender, integer num, string msg, key id) {
+        if (num == NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE) {
+            if (msg == READ_NOTECARD_COMMAND) {
+                process_notecard(sender, num, msg, id);
+            }
+            return;
+        }
+        
+        if (num != CARD_CONFIGURATOR_HUFFWARE_ID) return;  // not even slightly for us.
+        
+        if (msg == BEGIN_READING_NOTECARD_COMMAND) {
+            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+            signature_required = llList2String(parms, 0);
+            string prefixes_wrap = llList2String(parms, 1);
+//log_it("pref raw is: " + prefixes_wrap);
+            good_prefixes = llParseString2List(prefixes_wrap, [HUFFWARE_ITEM_SEPARATOR], []);
+//log_it("signature to find: " + signature_required);
+            initialize();
+//log_it("prefixes are: " + (string)good_prefixes);
+//log_it("began reading, memory left=" + (string)llGetFreeMemory());
+            return;
+        }
+        if (msg == READ_PARTICULAR_NOTECARD_COMMAND) {
+            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+            signature_required = llList2String(parms, 0);
+            string prefixes_wrap = llList2String(parms, 1);
+            string specific_card = llList2String(parms, 2);
+//log_it("pref raw is: " + prefixes_wrap);
+            good_prefixes = llParseString2List(prefixes_wrap, [HUFFWARE_ITEM_SEPARATOR], []);
+//log_it("signature to find: " + signature_required);
+            initialize_specific(specific_card);
+//log_it("prefixes are: " + (string)good_prefixes);
+//log_it("notecard is: " + specific_card);
+//log_it("began reading, memory left=" + (string)llGetFreeMemory());
+            return;
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/card_configurator_v8.1.txt b/huffware/huffotronic_updater_freebie_v5.3/card_configurator_v8.1.txt
deleted file mode 100755 (executable)
index 9653ec0..0000000
+++ /dev/null
@@ -1,499 +0,0 @@
-
-// huffware script: card configurator, by fred huffhines.
-//
-// processes a notecard with configuration info, then sends the information as packages of
-// configuration nuggest to a consuming script.  this is one level above the noteworthy script,
-// which simply reads the notecard.  this script keeps the config parsing out of higher-level
-// scripts.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-integer MAXIMUM_ITEMS_PER_BURST = 6;
-    // try this out as a good limit for the size of the sends.
-
-// global variables...
-
-string signature_required;
-    // sent to us when the request for configuration info is made.
-
-list good_prefixes;
-    // similarly, a set of prefixes for notecard lines that the calling script
-    // cares about.  if this is empty, then anything will match.
-
-string global_notecard_name;  // name of our notecard in the object's inventory.
-integer response_code;  // set to uniquely identify the notecard read in progress.
-list global_config_list;  // a collection of configuration parameters from our notecard.
-list global_responses;  // the items we want to send back to the requestor.
-
-// card configurator link message API:
-//////////////
-// do not redefine these constants.
-integer CARD_CONFIGURATOR_HUFFWARE_ID = 10042;
-    // the unique id within the huffware system for the card configurator script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-string BAD_NOTECARD_TEXT = "*badcrd*";
-    // the sign that we hated the notecards we found, or there were none.
-string FINISHED_READING_NOTECARDS = "**finished**";
-    // the sign that we are done plowing through the card we found.
-string BEGIN_READING_NOTECARD_COMMAND = "#read-cfg#";
-    // requests that the configurator find a good notecard and read its contents.
-    // it should send the contents via the alert below.  first parm is the signature and
-    // second is the wrapped list of valid item prefixes.
-string READ_PARTICULAR_NOTECARD_COMMAND = "#read-note#";
-    // requests that the configurator find a good notecard and read its contents.
-    // it should send the contents via the alert below.  first two parms are the same as
-    // begin reading notecard, and the third parameter is the name of the specific notecard.
-string CARD_CONFIG_RECEIVED_ALERT = "#cfg-event-upd#";
-    // this message is sent when the configurator has found some data updates or has finished
-    // reading the configuration file.
-//////////////
-
-// imported interfaces below...
-
-// requires noteworthy library v8.5 or better.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-// commands available via the noteworthy library:
-string BUSY_READING_INDICATOR = "busy_already";
-    // this return value indicates that the script is already in use by some other script.
-    // the calling script should try again later.
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be blank.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
-    // found) and as subsequent elements an embedded list that was read from the
-    // notecard.  this necessarily limits the size of the notecards that we can read
-    // and return.
-string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
-    // like the read notecard command, but specifies the notecard name to use.  only that
-    // specific notecard file will be consulted.  first and second parm are still signature
-    // and response code, third parm is the notecard name.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// this function fires off a request to the noteworthy library via a link message.
-// noteworthy will look for a notecard with our particular signature in it and
-// if it finds one, it will read the configuration therein.  an empty string is
-// returned if noteworthy couldn't find anything.
-request_configuration()
-{
-    global_notecard_name = "";  // reset any previous card.
-    // try to find a notecard with our configuration.
-    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([signature_required, response_code]);
-    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-         parms_sent);
-}
-
-request_specific_configuration()
-{
-    // try to find a notecard with our configuration.
-    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([signature_required, response_code, global_notecard_name]);
-    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_SPECIFIC_NOTECARD_COMMAND,
-         parms_sent);
-}
-
-// processes link messages received from the noteworthy library.
-process_notecard(integer which, integer num, string msg, key id)
-{
-    if (msg != READ_NOTECARD_COMMAND) return;  // not for us.
-    // process the result of reading the notecard.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string notecard_name = llList2String(parms, 0);
-    integer response_for = llList2Integer(parms, 1);
-    if (response_for != response_code) return;  // oops, this isn't for us.
-    if (notecard_name != BAD_NOTECARD_TEXT) {
-        // a valid notecard has been found.
-        global_notecard_name = notecard_name;  // record its name for later use.
-        // snag all but the first two elements for our config now.
-        global_config_list = llList2List(parms, 2, -1);
-        parms = [];  // toss the old copy.
-        // and process the file as a set of definitions.
-        process_ini_config();
-        send_data_burst();  // send any pending configs out.
-        if (notecard_name != NOTECARD_READ_CONTINUATION) {
-//log_it("sending final sentinel at end of card.");
-            // blast out a fake data burst that means we're done reading.
-            global_notecard_name = FINISHED_READING_NOTECARDS;
-            global_responses += [ FINISHED_READING_NOTECARDS ];
-            send_data_burst();
-        }
-//log_it("after config read, memory left=" + (string)llGetFreeMemory());
-    } else {
-        // we hated the notecards we found, or there were none.
-        // send a failure response.
-        llMessageLinked(LINK_THIS, CARD_CONFIGURATOR_HUFFWARE_ID + REPLY_DISTANCE,
-            CARD_CONFIG_RECEIVED_ALERT, wrap_parameters([BAD_NOTECARD_TEXT]));
-    }
-}
-
-///////////////
-
-// sends the currently held data out to whoever requested it.
-send_data_burst()
-{
-    if (!llGetListLength(global_responses)) return;  // nothing to send.
-//log_it("sending " + (string)llGetListLength(global_responses) + " items");
-    llMessageLinked(LINK_THIS, CARD_CONFIGURATOR_HUFFWARE_ID + REPLY_DISTANCE, CARD_CONFIG_RECEIVED_ALERT,
-        wrap_parameters([global_notecard_name] + global_responses));
-    global_responses = [];  // reset any items held.
-}
-
-// consumes the notecard in a very application specific way to retrieve our configuration items.
-// the example script only looks for two variables: name and description.  if those are found in
-// the sample card, then they are proudly shown.
-parse_variable_definition(string to_parse)
-{
-    string content;  // filled after finding a variable name.
-    list x_y = separate_variable_definition(to_parse);
-    string x = llList2String(x_y, 0);
-    if (!llGetListLength(good_prefixes)) {
-        global_responses += x_y;
-    } else {
-        integer indy;
-        for (indy = 0; indy < llGetListLength(good_prefixes); indy++) {
-            // if it's one of our desired prefixes, then we add it.
-            if (is_prefix(x, llList2String(good_prefixes, indy))) {
-                global_responses += x_y;
-                indy = llGetListLength(good_prefixes) + 5;  // skip rest of loop.
-            }
-        }
-    }
-    
-    if (llGetListLength(global_responses) > MAXIMUM_ITEMS_PER_BURST) {
-        send_data_burst();
-    }
-}
-
-// examines all entries that we got from the notecard to see if any contain definitions.
-// this is basically an INI file reader, but it uses a list instead of a file.
-// ini files provide a format with multiple sections of config information, like so:
-//    [section_1]
-//    name1=value1
-//    name2=value2 ...etc...
-//    [section_2]
-//    name1=value1 ...etc...
-process_ini_config()
-{
-//    log_it("scanning notecard for variable definitions...");
-    integer indy;
-    integer count = llGetListLength(global_config_list);
-    // iterate across the items in our configuration to look for ones that are not done yet.
-    for (indy = 0; indy < count; indy++) {
-        string line = llList2String(global_config_list, indy);
-//log_it("ini proc: " + line);
-        // search for a section beginning.
-        if (llGetSubString(line, 0, 0) == "[") {
-            // we found the start of a section name.  now read the contents.
-//            log_it("reading section: " + llGetSubString(line, 1, -2));
-//            global_responses += [ line, "e" ];
-            indy++;  // skip the section line.
-        }
-        integer sec_indy;
-        for (sec_indy = indy; sec_indy < count; sec_indy++) {
-            // read the lines in the section.
-            line = llList2String(global_config_list, sec_indy);
-            if (llGetSubString(line, 0, 0) != "[") {
-                // try to interpret this line as a variable setting.  this is just
-                // one example of a way to handle the config file; one might instead
-                // want to do something below once a whole section is read.
-                parse_variable_definition(line);
-            } else {
-                // we're at the beginning of a new section now, so start processing its
-                // configuration in the outer loop.
-                indy = sec_indy - 1;  // set indy to proper beginning of section.
-                sec_indy = count + 3;  // skip remainder of inner loop.
-            }
-        }
-        if (sec_indy == count) indy = count + 3;  // skip out of loop now.
-    }
-    global_config_list = [];  // we ate it!
-}
-
-initialize_specific(string specific_card)
-{
-    // reset our relevant variables.
-    global_notecard_name = specific_card;
-    global_config_list = [];
-    global_responses = [];
-
-    // request that the noteworthy library start looking for our notecard.
-    request_specific_configuration();
-}
-
-initialize()
-{
-    // reset our relevant variables.
-    global_notecard_name = "";
-    global_config_list = [];
-    global_responses = [];
-
-    // request that the noteworthy library start looking for our notecard.
-    request_configuration();
-}
-
-//////////////
-// from hufflets...
-//
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-integer find_substring(string full_string, string pattern)
-{
-    string full_lower = llToLower(full_string);
-    return llSubStringIndex(full_lower, pattern);
-}
-
-//////////////
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// strips the spaces off of the beginning and end of a string.
-string strip_spaces(string to_strip)
-{
-    // clean out initial spaces.
-    while (llGetSubString(to_strip, 0, 0) == " ")
-        to_strip = llDeleteSubString(to_strip, 0, 0);
-    // clean out ending spaces.
-    while (llGetSubString(to_strip, -1, -1) == " ")
-        to_strip = llDeleteSubString(to_strip, -1, -1);
-    return to_strip;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-///log_it("got x = " + x + " and y = " + y);
-    return [ strip_spaces(x), strip_spaces(y) ];
-}
-//
-// end hufflets
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();  // make sure newest addition is only version of script.
-    }
-
-    on_rez(integer parm) { state rerun; }
-
-    link_message(integer sender, integer num, string msg, key id) {
-        if (num == NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE) {
-            if (msg == READ_NOTECARD_COMMAND) {
-                process_notecard(sender, num, msg, id);
-            }
-            return;
-        }
-        
-        if (num != CARD_CONFIGURATOR_HUFFWARE_ID) return;  // not even slightly for us.
-        
-        if (msg == BEGIN_READING_NOTECARD_COMMAND) {
-            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-            signature_required = llList2String(parms, 0);
-            string prefixes_wrap = llList2String(parms, 1);
-//log_it("pref raw is: " + prefixes_wrap);
-            good_prefixes = llParseString2List(prefixes_wrap, [HUFFWARE_ITEM_SEPARATOR], []);
-//log_it("signature to find: " + signature_required);
-            initialize();
-//log_it("prefixes are: " + (string)good_prefixes);
-//log_it("began reading, memory left=" + (string)llGetFreeMemory());
-            return;
-        }
-        if (msg == READ_PARTICULAR_NOTECARD_COMMAND) {
-            list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-            signature_required = llList2String(parms, 0);
-            string prefixes_wrap = llList2String(parms, 1);
-            string specific_card = llList2String(parms, 2);
-//log_it("pref raw is: " + prefixes_wrap);
-            good_prefixes = llParseString2List(prefixes_wrap, [HUFFWARE_ITEM_SEPARATOR], []);
-//log_it("signature to find: " + signature_required);
-            initialize_specific(specific_card);
-//log_it("prefixes are: " + (string)good_prefixes);
-//log_it("notecard is: " + specific_card);
-//log_it("began reading, memory left=" + (string)llGetFreeMemory());
-            return;
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/clear_text_and_effects_v2.2.lsl b/huffware/huffotronic_updater_freebie_v5.3/clear_text_and_effects_v2.2.lsl
new file mode 100755 (executable)
index 0000000..d550a27
--- /dev/null
@@ -0,0 +1,150 @@
+
+// huffware script: clear text and effects, by fred huffhines
+//
+// a simple helper for cleaning the text off of objects after a script has
+// set the sit text or main text.  it also stops any particle systems that
+// had been running previously and stops any sensors.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+
+        llSetText("", <0,0,0>, 0);  // clear any text above object.
+        llSetSitText("Sit Here");  // reset sit text to default state.
+        llSetTouchText("Touch");  // similarly for touch.
+        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
+
+        llParticleSystem([]);  // turn off all particles.
+
+        llSensorRemove();  // stop any running sensors.
+
+        llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
+
+        llSetTextureAnim(0, ALL_SIDES, 0, 0, 0, 0, 0);  // stop texture animations.
+
+        llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
+        llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
+
+        // keep it from being physical and from disapparating.
+        llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE]);
+    }
+
+    // make sure that we apply these settings when the object is rezzed, if it
+    // had been stored with annoying text or whatever and needs to be cleared.
+    on_rez(integer parm) { llResetScript(); }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/clear_text_and_effects_v2.2.txt b/huffware/huffotronic_updater_freebie_v5.3/clear_text_and_effects_v2.2.txt
deleted file mode 100755 (executable)
index d550a27..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-
-// huffware script: clear text and effects, by fred huffhines
-//
-// a simple helper for cleaning the text off of objects after a script has
-// set the sit text or main text.  it also stops any particle systems that
-// had been running previously and stops any sensors.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-
-        llSetText("", <0,0,0>, 0);  // clear any text above object.
-        llSetSitText("Sit Here");  // reset sit text to default state.
-        llSetTouchText("Touch");  // similarly for touch.
-        llSitTarget(ZERO_VECTOR, ZERO_ROTATION);  // reset sit target position.
-
-        llParticleSystem([]);  // turn off all particles.
-
-        llSensorRemove();  // stop any running sensors.
-
-        llTargetOmega(<0.0, 0.0, 0.0>, 0, 1.0);  // stop rotations of object.
-
-        llSetTextureAnim(0, ALL_SIDES, 0, 0, 0, 0, 0);  // stop texture animations.
-
-        llSetLinkAlpha(LINK_SET, 1.0, ALL_SIDES);  // turn off any transparency.
-        llSetLinkColor(LINK_SET, <1.0, 1.0, 1.0>, ALL_SIDES);  // reset color to white.
-
-        // keep it from being physical and from disapparating.
-        llSetPrimitiveParams([PRIM_TEMP_ON_REZ, FALSE, PRIM_PHYSICS, FALSE]);
-    }
-
-    // make sure that we apply these settings when the object is rezzed, if it
-    // had been stored with annoying text or whatever and needs to be cleared.
-    on_rez(integer parm) { llResetScript(); }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/comfortable_sitting_v7.5.lsl b/huffware/huffotronic_updater_freebie_v5.3/comfortable_sitting_v7.5.lsl
new file mode 100755 (executable)
index 0000000..202c58f
--- /dev/null
@@ -0,0 +1,882 @@
+
+// huffware script: comfortable sitting, by fred huffhines.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////
+
+// global constants...
+
+string NOTEWORTHY_SIGNATURE = "#sitting";
+    // the notecard must begin with this as its first line for it to be
+    // recognized as our configuration card.
+
+//////////////
+
+// global variables that are loaded from a notecard.
+
+vector AVATAR_ROTATION = <0, 0, -90>;  // star chair.
+//vector AVATAR_ROTATION = <0, 0, 0>;
+    // the euler vector for rotation of the avatar after sitting, in degrees.
+    // the rotation vector should be tailored to the object.
+
+vector AVATAR_POSITION = <-0.1, -0.28, -0.1>;  // star chair.
+//vector AVATAR_POSITION = <0.34, 0, 0>;
+    // the position of the sitting offset from the object center.   also needs to be
+    // tailored to the particular object.
+
+integer GOTO_WHICH_FLOOR = 1;
+    // when serving as an elevator, this is a way to cause the teleport offset
+    // to go to a particular floor.  the real z position is calculated from
+    // this times the floor size in meters.  note that floors are numbered
+    // starting at 1 (one).
+    
+float FLOOR_SIZE_IN_METERS = 0.0;
+    // when the script is used in an elevator, this specifies the height of the
+    // floors.  our current scheme will only work if that is constant between
+    // the floors.
+
+float BASE_FLOOR_HEIGHT = 0.0;
+    // the position of the first floor in meters.  this will not affect the
+    // position calculations unless floor size is non-zero.
+
+integer UNSEAT_AFTERWARDS = FALSE;
+    // if this is true, then the avatar is unseated just after sitting down.
+    
+float PAUSE_BEFORE_EVICTION = 0.28;
+    // the number of seconds that the avatars get to sit before we pop them
+    // out of the chair/teleporter/whatever.
+
+vector CAMERA_EYE_OFFSET = <3, 2, 1.5>;  // star chair.
+    // the offset for the camera after the avatar sits down.
+//relative to the avatar?
+
+vector CAMERA_TARGET = <-3, 0, 1>;  // star chair.
+    // the location where the camera is looking at once the avatar sits down.
+//relative to the avatar?
+
+//////////////
+
+// global variables used in processing notecards...
+
+integer pending_response_id;  // set to uniquely identify the notecard read in progress.
+list global_config_list;  // a collection of configuration parameters from our notecard.
+integer global_config_index;  // allows wrap-around feature, which we don't use here.
+
+//////////////
+
+// interfaces for library scripts we rely on...
+
+// requires noteworthy library.
+// in this odd case, where we are trying to shrink script count, the noteworthy library
+// is embedded inside here.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be blank.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
+    // found) and as subsequent elements an embedded list that was read from the
+    // notecard.  this necessarily limits the size of the notecards that we can read
+    // and return.
+string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
+    // like the read notecard command, but specifies the notecard name to use.  only that
+    // specific notecard file will be consulted.  first and second parm are still signature
+    // and response code, third parm is the notecard name.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// establishes the sitting parameters including camera offsets.
+setup_seating_arrangements()
+{
+    llUnSit(llAvatarOnSitTarget());  // no one gets to ignore a script change.        
+    vector new_rot = AVATAR_ROTATION;
+    new_rot *= DEG_TO_RAD;  // convert to radians.
+    rotation quat = llEuler2Rot(new_rot);  // convert to quaternion.
+    // get our position set up and take into account the elevator position.
+    vector position = AVATAR_POSITION;
+//rename that variable to be "which floor to go to"
+    if (FLOOR_SIZE_IN_METERS != 0) {
+        vector temp = llGetPos();
+        integer my_floor = (integer) ((temp.z - BASE_FLOOR_HEIGHT ) / FLOOR_SIZE_IN_METERS) + 1;
+//log_it("my floor is " + (string)my_floor);
+        float add_in = (float)(GOTO_WHICH_FLOOR - my_floor) * FLOOR_SIZE_IN_METERS;
+//log_it("decided to add in z: " + (string)add_in);
+        position += <0, 0, add_in>;        
+    }
+    // also we make this absolute by taking out the object's own rotation.
+    // it's hard enough in life for z components to not mean z axis.
+    position /= llGetRot();
+    llSitTarget(position, quat / llGetRot());
+//hmmm: do we need same rot treatment on camera things?    
+//hmmm: trying it.
+    // now set the camera position to avoid having random viewpoint.
+    llSetCameraEyeOffset(CAMERA_EYE_OFFSET / llGetRot());
+    llSetCameraAtOffset(CAMERA_TARGET / llGetRot());
+}
+
+// this function fires off a request to the noteworthy library via a link message.
+// noteworthy will look for a notecard with our particular signature in it and
+// if it finds one, it will read the configuration therein.  an empty string is
+// returned if noteworthy couldn't find anything.
+request_configuration()
+{
+    // try to find a notecard with our configuration.
+    pending_response_id = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([NOTEWORTHY_SIGNATURE, pending_response_id]);
+//call direct into noteworthy.
+noteworthy_handle_link_message(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND, parms_sent);
+        
+//    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+//         parms_sent);
+}
+
+// processes link messages received from the noteworthy library.
+handle_link_message(integer which, integer num, string msg, key id)
+{
+    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
+            || (msg != READ_NOTECARD_COMMAND) )
+        return;  // not for us.
+//log_it("handl: msg=" + msg + " id=" + id);
+    // process the result of reading the notecard.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string notecard_name = llList2String(parms, 0);
+//log_it("raw is " + llList2String(parms, 1));
+    integer response_for = llList2Integer(parms, 1);
+//log_it("resp cod=" + pending_response_id + " but this for=" + response_for);
+//if (response_for != pending_response_id) log_it("bad response code???");    
+    if (response_for != pending_response_id) return;  // oops, this isn't for us.
+    if (notecard_name == BAD_NOTECARD_INDICATOR) {
+        // we hated the notecards we found, or there were none.
+        log_it("We apologize; there seem to be no notecards with a first line of '"
+            + NOTEWORTHY_SIGNATURE
+            + "'.  We can't read any configuration until that situation improves.");
+    } else {
+//log_it("got to handle link");
+        // snag all but the first two elements for our config now.
+        global_config_list += llList2List(parms, 2, -1);
+        // make sure we shouldn't keep going.
+        if (notecard_name != NOTECARD_READ_CONTINUATION) {
+            // a valid notecard has been found.
+            global_config_index = 0;  // we are starting over in the config list.
+//            log_it("read notecard \"" + notecard_name + "\":");
+            // and process the file as a set of definitions.
+            process_ini_config();
+            // now that we have a new set of parameters, use them.
+            setup_seating_arrangements();
+        }
+    }
+}
+
+///////////////
+
+// consumes the notecard in a very application specific way to retrieve our configuration items.
+// the example script only looks for two variables: name and description.  if those are found in
+// the sample card, then they are proudly shown.
+parse_variable_definition(string to_parse)
+{
+    string content;  // filled after finding a variable name.
+    if ( (content = get_variable_value(to_parse, "avatar_rotation")) != "") {
+        AVATAR_ROTATION = (vector)content;
+//        log_it("** got avatar_rotation of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "avatar_position")) != "") {
+        AVATAR_POSITION = (vector)content;
+//        log_it("** got avatar_position of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "goto_which_floor")) != "") {
+        GOTO_WHICH_FLOOR = (integer)content;
+//        log_it("** got GOTO_WHICH_FLOOR of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "floor_size_in_meters")) != "") {
+        FLOOR_SIZE_IN_METERS = (float)content;
+//        log_it("** got FLOOR_SIZE_IN_METERS of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "base_floor_height")) != "") {
+        BASE_FLOOR_HEIGHT = (float)content;
+//        log_it("** got BASE_FLOOR_HEIGHT of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "unseat_afterwards")) != "") {
+        UNSEAT_AFTERWARDS = (integer)content;
+//        log_it("** got unseat_afterwards of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "pause_before_eviction")) != "") {
+        PAUSE_BEFORE_EVICTION = (float)content;
+//        log_it("** got pause_before_eviction of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "camera_eye_offset")) != "") {
+        CAMERA_EYE_OFFSET = (vector)content;
+//        log_it("** got camera_eye_offset of '" + content + "'");
+    } else if ( (content = get_variable_value(to_parse, "camera_target")) != "") {
+        CAMERA_TARGET = (vector)content;
+//        log_it("** got camera_target of '" + content + "'");
+//    } else {
+//        log_it("unknown variable seen: " + to_parse);
+    }
+}
+
+initialize()
+{
+    // reset our relevant variables.
+    global_config_list = [];
+    global_config_index = 0;
+
+    // announce that we're open for business.
+///    log_it("started, free mem=" + (string)llGetFreeMemory());
+
+    // request that the noteworthy library start looking for our notecard.
+    request_configuration();
+    
+    integer indy = 32;
+    while (indy >= 0) {
+        indy = find_in_inventory_partial("noteworthy", INVENTORY_SCRIPT);
+        if (indy >= 0) {
+            llRemoveInventory(llGetInventoryName(INVENTORY_SCRIPT, indy));
+        }
+    }
+    
+}
+
+//////////////
+// from hufflets...
+//
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// strips the spaces off of the beginning and end of a string.
+string strip_spaces(string to_strip)
+{
+    // clean out initial spaces.
+    while (llGetSubString(to_strip, 0, 0) == " ")
+        to_strip = llDeleteSubString(to_strip, 0, 0);
+    // clean out ending spaces.
+    while (llGetSubString(to_strip, -1, -1) == " ")
+        to_strip = llDeleteSubString(to_strip, -1, -1);
+    return to_strip;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+    return [ strip_spaces(x), strip_spaces(y) ];
+}
+
+// returns a non-empty string if "to_check" defines a value for "variable_name".
+// this must be in the form "X=Y", where X is the variable_name and Y is the value.
+string get_variable_value(string to_check, string variable_name)
+{
+    list x_y = separate_variable_definition(to_check);
+    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
+    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
+    return llList2String(x_y, 1);  // a match!
+}
+
+// examines all entries that we got from the notecard to see if any contain definitions.
+// this is basically an INI file reader, but it uses a list instead of a file.
+// ini files provide a format with multiple sections of config information, like so:
+//    [section_1]
+//    name1=value1
+//    name2=value2 ...etc...
+//    [section_2]
+//    name1=value1 ...etc...
+process_ini_config()
+{
+//    log_it("scanning notecard for variable definitions...");
+    integer indy;
+    integer count = llGetListLength(global_config_list);
+    string section_name;  // set later if we see one.
+
+    // iterate across the items in our configuration to look for ones that are not done yet.            
+    for (indy = global_config_index; indy < count; indy++) {
+        string line = llList2String(global_config_list, indy);
+        // search for a section beginning.
+        if (llGetSubString(line, 0, 0) == "[") {
+            // we found the start of a section name.  now read the contents.
+            indy++;  // skip section line.
+            section_name = llGetSubString(line, 1, -2);
+            log_it("reading section: " + section_name);
+        }
+        integer sec_indy;
+        for (sec_indy = indy; sec_indy < count; sec_indy++) {
+            // read the lines in the section.
+            line = llList2String(global_config_list, sec_indy);
+            if (llGetSubString(line, 0, 0) != "[") {
+                // try to interpret this line as a variable setting.  this is just
+                // one example of a way to handle the config file; one might instead
+                // want to do something below once a whole section is read.
+                parse_variable_definition(line);
+                indy = sec_indy;  // track that we've passed this line.
+            } else {
+                // we're at the beginning of a new section now, so start processing its
+                // configuration in the outer loop.
+                indy = sec_indy - 1;  // set indy to proper beginning of section.
+                global_config_index = indy;  // remember where we had read to.
+                sec_indy = count + 3;  // skip remainder of inner loop.
+            }
+        }
+    }
+
+    global_config_index = 0;  // reset outer position if want to re-read.
+}
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory_partial(string name_to_find, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 1.9.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+//
+// example usage of the auto-retirement script:
+//
+// default {
+//    state_entry() {
+//        auto_retire();  // make sure newest addition is only version of script.
+//    }
+// }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                if ((float)inv_version_string < (float)version_string) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
+        
+    string basename = to_chop_up;  // script name with no version attached.
+    
+    integer posn;
+    // minimum script name is 2 characters plus version.
+    for (posn = llStringLength(to_chop_up) - 1;
+        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
+        posn--) {
+        // find the space.  do nothing else.
+    }
+    if (posn < 2) return [];  // no space found.
+    string full_suffix = llGetSubString(to_chop_up, posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets
+//////////////
+
+//////////////
+// from noteworthy:
+
+// huffware script: noteworthy library, by fred huffhines.
+//
+// a handy approach to reading a notecard.  this version supports requiring
+// a 'signature' in the notecard's first line, so that multiple notecards can
+// exist in an object without being misinterpreted.  the script is accessed via
+// its link message API, so it can be used in an object without all this code
+// needing to be embedded in another script.  it also supports queuing up requests
+// to read notecards, so multiple scripts can use it to read their specific
+// notecards without any special handling (besides waiting a bit longer).
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants that can be adapted to your needs...
+
+integer DEBUGGING = FALSE;
+    // if this is true, then a lot of extra noise is generated when notecards are read.
+
+float TIME_OUT_ON_ONE_NOTECARD = 120.0;
+    // we allow one line of a notecard this long to be read before we decide it's hosed.
+    // some sims are very very slow, and a time-out of one minute has been found lacking;
+    // we saw at least one case where the first notecard line to be read took longer than
+    // 60 seconds.  that's why we keep cranking this time-out up...
+
+// constants that should not be changed...
+
+// outcomes from handling a line in a notecard.
+integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
+integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
+integer DONE_READING = -10;  // the notecard is finished being read.
+
+integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
+
+integer MAXIMUM_LINES_USED = 4;
+    // we will read this many lines at a time from the appropriate notecard.
+// global variables...
+
+string requested_signature = "";
+    // if this is non-empty, then it must be found in the first line of the script.
+
+integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
+
+string global_notecard_name;  // the name of the card we're reading now.
+key global_query_id = NULL_KEY;  // the identifier of our data query.
+integer current_response_code = 0;  // the code that our client uses for its reading.
+list global_query_contents;  // the lines we have read from the notecard.
+
+integer line_number = 0;  // which line are we at in notecard?
+
+integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
+
+integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
+
+list pending_signatures;  // signatures from queued requests for reading.
+list pending_response_codes;  // response codes for the queued requests.
+list pending_notecard_names;  // card names if it's a specific request.
+
+//////////////
+
+startup_initialize()
+{
+    llSetTimerEvent(0.0);
+    pending_signatures = [];
+    pending_response_codes = [];
+    pending_notecard_names = [];
+    current_response_code = 0;
+}
+
+reset_for_reading(string signature, integer response_code_in)
+{
+    requested_signature = signature;
+    current_response_code = response_code_in;
+    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
+    global_query_contents = [];
+    global_notecard_name = "";
+    line_number = 0;
+    found_signature_line = FALSE;
+    trying_notecard_at = -1;
+    global_query_id = NULL_KEY;
+}
+
+// use the existing global notecard setting to start reading.
+select_specific_notecard()
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    line_number = 0;  // reset line number again.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// picks the notecard at the "index" (from 0 to num_notecards - 1) and
+// starts reading it.
+select_notecard(integer index)
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
+    if (card_specified == "") return;   // not good.  bad index.
+    global_notecard_name = card_specified;
+    line_number = 0;  // reset line number again.
+    // we have a new file name, so load up the destinations, hopefully.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// increments our index in the count of notecards that the object has, and start
+// reading the next notecard (at the index).
+integer try_next_notecard()
+{
+    if (only_read_one_notecard) {
+        return FALSE;  // we were only going to try one.
+    }
+    // reset some values that might have applied before.
+    global_notecard_name = "";
+    // skip to the next card.
+    trying_notecard_at++;
+    // make sure we're not over the count of cards.
+    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
+        // this is a problem.  we didn't find anything suitable.
+        return FALSE;
+    }
+    // so, now we'll try the next notecard to look for our signature.
+    select_notecard(trying_notecard_at);
+    return TRUE;
+}
+
+// process a line of text that we received from the current notecard.
+integer handle_notecard_line(key query_id, string data)
+{
+    // if we're not at the end of the notecard we're reading...
+    if (data != EOF) {
+        // there's more to read in the notecard still.
+        if (data != "") {
+            // make sure we even have a signature to look for.
+            if (!found_signature_line && (requested_signature == "")) {
+                // no signature means that we always find it.
+                found_signature_line = TRUE;
+            }
+            // did we already get our signature?  if not, see if this is it.
+            if (!found_signature_line && (data != requested_signature) ) {
+                // this is a bad notecard.  skip it.
+                if (!try_next_notecard()) {
+                    // we have no more to work with.
+                    return BAD_NOTECARD;
+                }
+                return STILL_READING;  // we'll keep going.
+            } else if (!found_signature_line && (data == requested_signature) ) {
+                // this is a good signature line, so record that and then skip it.
+                found_signature_line = TRUE;
+            } else {
+                if (DEBUGGING
+                    && ( ( (requested_signature == "") && (line_number == 0) )
+                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
+                    log_it("started reading " + global_notecard_name + "...");
+                }
+                // don't record any lines that are comments.
+                if ( (llGetSubString(data, 0, 0) != "#")
+                    && (llGetSubString(data, 0, 0) != ";") ) {
+                    // add the non-blank line to our list.
+                    global_query_contents += data;
+                    // make sure we still have enough space to keep going.
+                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
+                        // ooh, make sure we pause before blowing our heap&stack.
+                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
+                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
+                    }
+                }
+            }
+        }
+        line_number++;  // increase the line count.
+        // reset the timer rather than timing out, if we actually got some data.
+        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
+        // request the next line from the notecard.
+        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
+        if (global_query_id == NULL_KEY) {
+//log_it("failed to restart notecard reading.");
+            return DONE_READING;
+//is that the best outcome?
+        }
+        return STILL_READING;
+    } else {
+        // that's the end of the notecard.  we need some minimal verification that it
+        // wasn't full of garbage.
+        if (!found_signature_line) {
+            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
+            if (!try_next_notecard()) {
+                return BAD_NOTECARD;  // we failed to find a good line?
+            } else {
+                // the next notecard's coming through now.
+                return STILL_READING;
+            }
+        } else {
+//            if (DEBUGGING) log_it("found signature.");
+            // saw the signature line, so this is a good one.
+            return DONE_READING;
+        }
+    }
+}
+
+// only sends reply; does not reset notecard process.
+send_reply(integer destination, list parms, string command,
+    integer include_query)
+{
+//log_it("froyo: curre code=" + current_response_code);
+//integer items = llGetListLength(parms);
+//if (include_query) items += llGetListLength(global_query_contents);
+//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
+
+   if (!include_query) {
+        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+    } else {
+        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command,
+            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
+    }
+    global_query_contents = [];
+//log_it("post-sending, mem=" + (string)llGetFreeMemory());
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply_and_reset(integer destination, list parms, string command,
+    integer include_query)
+{
+    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
+    send_reply(destination, parms, command, include_query);
+//log_it("about to reset response code");
+    current_response_code = 0;  // reset back to default so we can start another read.
+    global_query_id = NULL_KEY;  // reset so we accept no more data.
+}
+
+// if there are other pending notecard reads, this goes to the next one listed.
+dequeue_next_request()
+{
+    if (llGetListLength(pending_signatures)) {
+        // get the info from the next pending item.
+        string sig = llList2String(pending_signatures, 0);
+        integer response_code_temp = llList2Integer(pending_response_codes, 0);
+        string notecard = llList2String(pending_notecard_names, 0);
+        // whack the head of the queue since we grabbed the info.
+        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
+        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
+        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
+        if (llStringLength(notecard)) {
+            global_notecard_name = notecard;
+            select_specific_notecard();
+        } else {
+            reset_for_reading(sig, response_code_temp);
+        }
+    }
+}
+
+// deals with one data server answer from the notecard.
+process_notecard_line(key query_id, string data)
+{
+    // try to consume a line from the notecard.
+    integer outcome = handle_notecard_line(query_id, data);
+    if (outcome == DONE_READING) {
+        // that was a valid notecard and we read all of it.
+        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
+        // send back the results.
+        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
+            READ_NOTECARD_COMMAND, TRUE);
+    } else if (outcome == BAD_NOTECARD) {
+        // bail; this problem must be addressed by other means.
+        if (DEBUGGING) log_it("failed to find an appropriate notecard");
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    } else if (outcome == STILL_READING) {
+        // we have a good card and are still processing it.
+        return;
+    } else {
+        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
+        // again, bail out.  we have no idea what happened with this.
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    }
+    // if we have reached here, we should crank up the next queued notecard reading.
+    dequeue_next_request();
+}
+
+// processes requests from our users.
+noteworthy_handle_link_message(integer which, integer num, string msg, key id)
+{
+    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
+
+    if (msg == READ_NOTECARD_COMMAND) {
+        only_read_one_notecard = FALSE;  // general inquiry for any card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read notecard--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code_temp = llList2Integer(parms, 1);
+//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code_temp);
+            if (!try_next_notecard()) {
+                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
+                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code_temp ],
+                    READ_NOTECARD_COMMAND, FALSE);
+                return;
+            }
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code_temp;
+//holding:            pending_notecard_names += "";
+//holding:        }
+    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
+        only_read_one_notecard = TRUE;  // they want one particular card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read specific--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code_temp = llList2Integer(parms, 1);
+        string notecard_name = llList2String(parms, 2);
+//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code_temp);
+            global_notecard_name = notecard_name;  // set our global.
+            select_specific_notecard();
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code_temp;
+//holding:            pending_notecard_names += notecard_name;
+//holding:        }
+    }
+}
+
+    
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();  // make sure newest addition is only version of script.
+/////not needed now        llSleep(1.0);  // snooze just a bit to let noteworthy start up?
+        startup_initialize();
+        initialize();  // start asking about the notecards.
+        setup_seating_arrangements();  // use our current defaults for sitting posn.
+    }
+
+    on_rez(integer parm) { llResetScript(); }
+
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+//            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
+            llResetScript(); 
+        }
+        if (!(change & CHANGED_LINK)) return;  // don't care.
+        if (!UNSEAT_AFTERWARDS) return;  // nothing else below is needed.
+        if (llAvatarOnSitTarget() == NULL_KEY) return;  // no one there, so ditto.
+        // now give them a bit of time to rest before dumping them.
+        llSetTimerEvent(PAUSE_BEFORE_EVICTION);
+    }
+    
+    timer() {
+        if (current_response_code != 0) {
+            llSetTimerEvent(0.0);  // stop any timer now.
+            // let the caller know this has failed out.
+            if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
+            send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+                READ_NOTECARD_COMMAND, FALSE);
+            current_response_code = 0;  // we gave up on that one.
+            dequeue_next_request();  // get next reading started if we have anything to read.
+        } else {
+            // perform short range teleport, effectively...
+            llUnSit(llAvatarOnSitTarget());  // ha, got that guy back up.
+            llSetTimerEvent(0.0);  // reset timer.
+        }
+    }
+
+    // process the response from the noteworthy library.
+    link_message(integer which, integer num, string msg, key id)
+    { handle_link_message(which, num, msg, id); }
+
+    dataserver(key query_id, string data) {
+        // make sure this data is for us.
+        if (global_query_id != query_id) return;
+        // yep, seems to be.
+        process_notecard_line(query_id, data);
+    }            
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/comfortable_sitting_v7.5.txt b/huffware/huffotronic_updater_freebie_v5.3/comfortable_sitting_v7.5.txt
deleted file mode 100755 (executable)
index 202c58f..0000000
+++ /dev/null
@@ -1,882 +0,0 @@
-
-// huffware script: comfortable sitting, by fred huffhines.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////
-
-// global constants...
-
-string NOTEWORTHY_SIGNATURE = "#sitting";
-    // the notecard must begin with this as its first line for it to be
-    // recognized as our configuration card.
-
-//////////////
-
-// global variables that are loaded from a notecard.
-
-vector AVATAR_ROTATION = <0, 0, -90>;  // star chair.
-//vector AVATAR_ROTATION = <0, 0, 0>;
-    // the euler vector for rotation of the avatar after sitting, in degrees.
-    // the rotation vector should be tailored to the object.
-
-vector AVATAR_POSITION = <-0.1, -0.28, -0.1>;  // star chair.
-//vector AVATAR_POSITION = <0.34, 0, 0>;
-    // the position of the sitting offset from the object center.   also needs to be
-    // tailored to the particular object.
-
-integer GOTO_WHICH_FLOOR = 1;
-    // when serving as an elevator, this is a way to cause the teleport offset
-    // to go to a particular floor.  the real z position is calculated from
-    // this times the floor size in meters.  note that floors are numbered
-    // starting at 1 (one).
-    
-float FLOOR_SIZE_IN_METERS = 0.0;
-    // when the script is used in an elevator, this specifies the height of the
-    // floors.  our current scheme will only work if that is constant between
-    // the floors.
-
-float BASE_FLOOR_HEIGHT = 0.0;
-    // the position of the first floor in meters.  this will not affect the
-    // position calculations unless floor size is non-zero.
-
-integer UNSEAT_AFTERWARDS = FALSE;
-    // if this is true, then the avatar is unseated just after sitting down.
-    
-float PAUSE_BEFORE_EVICTION = 0.28;
-    // the number of seconds that the avatars get to sit before we pop them
-    // out of the chair/teleporter/whatever.
-
-vector CAMERA_EYE_OFFSET = <3, 2, 1.5>;  // star chair.
-    // the offset for the camera after the avatar sits down.
-//relative to the avatar?
-
-vector CAMERA_TARGET = <-3, 0, 1>;  // star chair.
-    // the location where the camera is looking at once the avatar sits down.
-//relative to the avatar?
-
-//////////////
-
-// global variables used in processing notecards...
-
-integer pending_response_id;  // set to uniquely identify the notecard read in progress.
-list global_config_list;  // a collection of configuration parameters from our notecard.
-integer global_config_index;  // allows wrap-around feature, which we don't use here.
-
-//////////////
-
-// interfaces for library scripts we rely on...
-
-// requires noteworthy library.
-// in this odd case, where we are trying to shrink script count, the noteworthy library
-// is embedded inside here.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be blank.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
-    // found) and as subsequent elements an embedded list that was read from the
-    // notecard.  this necessarily limits the size of the notecards that we can read
-    // and return.
-string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
-    // like the read notecard command, but specifies the notecard name to use.  only that
-    // specific notecard file will be consulted.  first and second parm are still signature
-    // and response code, third parm is the notecard name.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// establishes the sitting parameters including camera offsets.
-setup_seating_arrangements()
-{
-    llUnSit(llAvatarOnSitTarget());  // no one gets to ignore a script change.        
-    vector new_rot = AVATAR_ROTATION;
-    new_rot *= DEG_TO_RAD;  // convert to radians.
-    rotation quat = llEuler2Rot(new_rot);  // convert to quaternion.
-    // get our position set up and take into account the elevator position.
-    vector position = AVATAR_POSITION;
-//rename that variable to be "which floor to go to"
-    if (FLOOR_SIZE_IN_METERS != 0) {
-        vector temp = llGetPos();
-        integer my_floor = (integer) ((temp.z - BASE_FLOOR_HEIGHT ) / FLOOR_SIZE_IN_METERS) + 1;
-//log_it("my floor is " + (string)my_floor);
-        float add_in = (float)(GOTO_WHICH_FLOOR - my_floor) * FLOOR_SIZE_IN_METERS;
-//log_it("decided to add in z: " + (string)add_in);
-        position += <0, 0, add_in>;        
-    }
-    // also we make this absolute by taking out the object's own rotation.
-    // it's hard enough in life for z components to not mean z axis.
-    position /= llGetRot();
-    llSitTarget(position, quat / llGetRot());
-//hmmm: do we need same rot treatment on camera things?    
-//hmmm: trying it.
-    // now set the camera position to avoid having random viewpoint.
-    llSetCameraEyeOffset(CAMERA_EYE_OFFSET / llGetRot());
-    llSetCameraAtOffset(CAMERA_TARGET / llGetRot());
-}
-
-// this function fires off a request to the noteworthy library via a link message.
-// noteworthy will look for a notecard with our particular signature in it and
-// if it finds one, it will read the configuration therein.  an empty string is
-// returned if noteworthy couldn't find anything.
-request_configuration()
-{
-    // try to find a notecard with our configuration.
-    pending_response_id = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([NOTEWORTHY_SIGNATURE, pending_response_id]);
-//call direct into noteworthy.
-noteworthy_handle_link_message(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND, parms_sent);
-        
-//    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-//         parms_sent);
-}
-
-// processes link messages received from the noteworthy library.
-handle_link_message(integer which, integer num, string msg, key id)
-{
-    if ( (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
-            || (msg != READ_NOTECARD_COMMAND) )
-        return;  // not for us.
-//log_it("handl: msg=" + msg + " id=" + id);
-    // process the result of reading the notecard.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string notecard_name = llList2String(parms, 0);
-//log_it("raw is " + llList2String(parms, 1));
-    integer response_for = llList2Integer(parms, 1);
-//log_it("resp cod=" + pending_response_id + " but this for=" + response_for);
-//if (response_for != pending_response_id) log_it("bad response code???");    
-    if (response_for != pending_response_id) return;  // oops, this isn't for us.
-    if (notecard_name == BAD_NOTECARD_INDICATOR) {
-        // we hated the notecards we found, or there were none.
-        log_it("We apologize; there seem to be no notecards with a first line of '"
-            + NOTEWORTHY_SIGNATURE
-            + "'.  We can't read any configuration until that situation improves.");
-    } else {
-//log_it("got to handle link");
-        // snag all but the first two elements for our config now.
-        global_config_list += llList2List(parms, 2, -1);
-        // make sure we shouldn't keep going.
-        if (notecard_name != NOTECARD_READ_CONTINUATION) {
-            // a valid notecard has been found.
-            global_config_index = 0;  // we are starting over in the config list.
-//            log_it("read notecard \"" + notecard_name + "\":");
-            // and process the file as a set of definitions.
-            process_ini_config();
-            // now that we have a new set of parameters, use them.
-            setup_seating_arrangements();
-        }
-    }
-}
-
-///////////////
-
-// consumes the notecard in a very application specific way to retrieve our configuration items.
-// the example script only looks for two variables: name and description.  if those are found in
-// the sample card, then they are proudly shown.
-parse_variable_definition(string to_parse)
-{
-    string content;  // filled after finding a variable name.
-    if ( (content = get_variable_value(to_parse, "avatar_rotation")) != "") {
-        AVATAR_ROTATION = (vector)content;
-//        log_it("** got avatar_rotation of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "avatar_position")) != "") {
-        AVATAR_POSITION = (vector)content;
-//        log_it("** got avatar_position of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "goto_which_floor")) != "") {
-        GOTO_WHICH_FLOOR = (integer)content;
-//        log_it("** got GOTO_WHICH_FLOOR of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "floor_size_in_meters")) != "") {
-        FLOOR_SIZE_IN_METERS = (float)content;
-//        log_it("** got FLOOR_SIZE_IN_METERS of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "base_floor_height")) != "") {
-        BASE_FLOOR_HEIGHT = (float)content;
-//        log_it("** got BASE_FLOOR_HEIGHT of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "unseat_afterwards")) != "") {
-        UNSEAT_AFTERWARDS = (integer)content;
-//        log_it("** got unseat_afterwards of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "pause_before_eviction")) != "") {
-        PAUSE_BEFORE_EVICTION = (float)content;
-//        log_it("** got pause_before_eviction of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "camera_eye_offset")) != "") {
-        CAMERA_EYE_OFFSET = (vector)content;
-//        log_it("** got camera_eye_offset of '" + content + "'");
-    } else if ( (content = get_variable_value(to_parse, "camera_target")) != "") {
-        CAMERA_TARGET = (vector)content;
-//        log_it("** got camera_target of '" + content + "'");
-//    } else {
-//        log_it("unknown variable seen: " + to_parse);
-    }
-}
-
-initialize()
-{
-    // reset our relevant variables.
-    global_config_list = [];
-    global_config_index = 0;
-
-    // announce that we're open for business.
-///    log_it("started, free mem=" + (string)llGetFreeMemory());
-
-    // request that the noteworthy library start looking for our notecard.
-    request_configuration();
-    
-    integer indy = 32;
-    while (indy >= 0) {
-        indy = find_in_inventory_partial("noteworthy", INVENTORY_SCRIPT);
-        if (indy >= 0) {
-            llRemoveInventory(llGetInventoryName(INVENTORY_SCRIPT, indy));
-        }
-    }
-    
-}
-
-//////////////
-// from hufflets...
-//
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// strips the spaces off of the beginning and end of a string.
-string strip_spaces(string to_strip)
-{
-    // clean out initial spaces.
-    while (llGetSubString(to_strip, 0, 0) == " ")
-        to_strip = llDeleteSubString(to_strip, 0, 0);
-    // clean out ending spaces.
-    while (llGetSubString(to_strip, -1, -1) == " ")
-        to_strip = llDeleteSubString(to_strip, -1, -1);
-    return to_strip;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-    return [ strip_spaces(x), strip_spaces(y) ];
-}
-
-// returns a non-empty string if "to_check" defines a value for "variable_name".
-// this must be in the form "X=Y", where X is the variable_name and Y is the value.
-string get_variable_value(string to_check, string variable_name)
-{
-    list x_y = separate_variable_definition(to_check);
-    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
-    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
-    return llList2String(x_y, 1);  // a match!
-}
-
-// examines all entries that we got from the notecard to see if any contain definitions.
-// this is basically an INI file reader, but it uses a list instead of a file.
-// ini files provide a format with multiple sections of config information, like so:
-//    [section_1]
-//    name1=value1
-//    name2=value2 ...etc...
-//    [section_2]
-//    name1=value1 ...etc...
-process_ini_config()
-{
-//    log_it("scanning notecard for variable definitions...");
-    integer indy;
-    integer count = llGetListLength(global_config_list);
-    string section_name;  // set later if we see one.
-
-    // iterate across the items in our configuration to look for ones that are not done yet.            
-    for (indy = global_config_index; indy < count; indy++) {
-        string line = llList2String(global_config_list, indy);
-        // search for a section beginning.
-        if (llGetSubString(line, 0, 0) == "[") {
-            // we found the start of a section name.  now read the contents.
-            indy++;  // skip section line.
-            section_name = llGetSubString(line, 1, -2);
-            log_it("reading section: " + section_name);
-        }
-        integer sec_indy;
-        for (sec_indy = indy; sec_indy < count; sec_indy++) {
-            // read the lines in the section.
-            line = llList2String(global_config_list, sec_indy);
-            if (llGetSubString(line, 0, 0) != "[") {
-                // try to interpret this line as a variable setting.  this is just
-                // one example of a way to handle the config file; one might instead
-                // want to do something below once a whole section is read.
-                parse_variable_definition(line);
-                indy = sec_indy;  // track that we've passed this line.
-            } else {
-                // we're at the beginning of a new section now, so start processing its
-                // configuration in the outer loop.
-                indy = sec_indy - 1;  // set indy to proper beginning of section.
-                global_config_index = indy;  // remember where we had read to.
-                sec_indy = count + 3;  // skip remainder of inner loop.
-            }
-        }
-    }
-
-    global_config_index = 0;  // reset outer position if want to re-read.
-}
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory_partial(string name_to_find, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 1.9.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-//
-// example usage of the auto-retirement script:
-//
-// default {
-//    state_entry() {
-//        auto_retire();  // make sure newest addition is only version of script.
-//    }
-// }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                if ((float)inv_version_string < (float)version_string) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    if (llSubStringIndex(to_chop_up, " ") < 0) return [];  // no space found, not a valid name to work on.
-        
-    string basename = to_chop_up;  // script name with no version attached.
-    
-    integer posn;
-    // minimum script name is 2 characters plus version.
-    for (posn = llStringLength(to_chop_up) - 1;
-        (posn >= 2) && (llGetSubString(to_chop_up, posn, posn) != " ");
-        posn--) {
-        // find the space.  do nothing else.
-    }
-    if (posn < 2) return [];  // no space found.
-    string full_suffix = llGetSubString(to_chop_up, posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets
-//////////////
-
-//////////////
-// from noteworthy:
-
-// huffware script: noteworthy library, by fred huffhines.
-//
-// a handy approach to reading a notecard.  this version supports requiring
-// a 'signature' in the notecard's first line, so that multiple notecards can
-// exist in an object without being misinterpreted.  the script is accessed via
-// its link message API, so it can be used in an object without all this code
-// needing to be embedded in another script.  it also supports queuing up requests
-// to read notecards, so multiple scripts can use it to read their specific
-// notecards without any special handling (besides waiting a bit longer).
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants that can be adapted to your needs...
-
-integer DEBUGGING = FALSE;
-    // if this is true, then a lot of extra noise is generated when notecards are read.
-
-float TIME_OUT_ON_ONE_NOTECARD = 120.0;
-    // we allow one line of a notecard this long to be read before we decide it's hosed.
-    // some sims are very very slow, and a time-out of one minute has been found lacking;
-    // we saw at least one case where the first notecard line to be read took longer than
-    // 60 seconds.  that's why we keep cranking this time-out up...
-
-// constants that should not be changed...
-
-// outcomes from handling a line in a notecard.
-integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
-integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
-integer DONE_READING = -10;  // the notecard is finished being read.
-
-integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
-
-integer MAXIMUM_LINES_USED = 4;
-    // we will read this many lines at a time from the appropriate notecard.
-// global variables...
-
-string requested_signature = "";
-    // if this is non-empty, then it must be found in the first line of the script.
-
-integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
-
-string global_notecard_name;  // the name of the card we're reading now.
-key global_query_id = NULL_KEY;  // the identifier of our data query.
-integer current_response_code = 0;  // the code that our client uses for its reading.
-list global_query_contents;  // the lines we have read from the notecard.
-
-integer line_number = 0;  // which line are we at in notecard?
-
-integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
-
-integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
-
-list pending_signatures;  // signatures from queued requests for reading.
-list pending_response_codes;  // response codes for the queued requests.
-list pending_notecard_names;  // card names if it's a specific request.
-
-//////////////
-
-startup_initialize()
-{
-    llSetTimerEvent(0.0);
-    pending_signatures = [];
-    pending_response_codes = [];
-    pending_notecard_names = [];
-    current_response_code = 0;
-}
-
-reset_for_reading(string signature, integer response_code_in)
-{
-    requested_signature = signature;
-    current_response_code = response_code_in;
-    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
-    global_query_contents = [];
-    global_notecard_name = "";
-    line_number = 0;
-    found_signature_line = FALSE;
-    trying_notecard_at = -1;
-    global_query_id = NULL_KEY;
-}
-
-// use the existing global notecard setting to start reading.
-select_specific_notecard()
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    line_number = 0;  // reset line number again.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// picks the notecard at the "index" (from 0 to num_notecards - 1) and
-// starts reading it.
-select_notecard(integer index)
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
-    if (card_specified == "") return;   // not good.  bad index.
-    global_notecard_name = card_specified;
-    line_number = 0;  // reset line number again.
-    // we have a new file name, so load up the destinations, hopefully.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// increments our index in the count of notecards that the object has, and start
-// reading the next notecard (at the index).
-integer try_next_notecard()
-{
-    if (only_read_one_notecard) {
-        return FALSE;  // we were only going to try one.
-    }
-    // reset some values that might have applied before.
-    global_notecard_name = "";
-    // skip to the next card.
-    trying_notecard_at++;
-    // make sure we're not over the count of cards.
-    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
-        // this is a problem.  we didn't find anything suitable.
-        return FALSE;
-    }
-    // so, now we'll try the next notecard to look for our signature.
-    select_notecard(trying_notecard_at);
-    return TRUE;
-}
-
-// process a line of text that we received from the current notecard.
-integer handle_notecard_line(key query_id, string data)
-{
-    // if we're not at the end of the notecard we're reading...
-    if (data != EOF) {
-        // there's more to read in the notecard still.
-        if (data != "") {
-            // make sure we even have a signature to look for.
-            if (!found_signature_line && (requested_signature == "")) {
-                // no signature means that we always find it.
-                found_signature_line = TRUE;
-            }
-            // did we already get our signature?  if not, see if this is it.
-            if (!found_signature_line && (data != requested_signature) ) {
-                // this is a bad notecard.  skip it.
-                if (!try_next_notecard()) {
-                    // we have no more to work with.
-                    return BAD_NOTECARD;
-                }
-                return STILL_READING;  // we'll keep going.
-            } else if (!found_signature_line && (data == requested_signature) ) {
-                // this is a good signature line, so record that and then skip it.
-                found_signature_line = TRUE;
-            } else {
-                if (DEBUGGING
-                    && ( ( (requested_signature == "") && (line_number == 0) )
-                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
-                    log_it("started reading " + global_notecard_name + "...");
-                }
-                // don't record any lines that are comments.
-                if ( (llGetSubString(data, 0, 0) != "#")
-                    && (llGetSubString(data, 0, 0) != ";") ) {
-                    // add the non-blank line to our list.
-                    global_query_contents += data;
-                    // make sure we still have enough space to keep going.
-                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
-                        // ooh, make sure we pause before blowing our heap&stack.
-                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
-                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
-                    }
-                }
-            }
-        }
-        line_number++;  // increase the line count.
-        // reset the timer rather than timing out, if we actually got some data.
-        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
-        // request the next line from the notecard.
-        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
-        if (global_query_id == NULL_KEY) {
-//log_it("failed to restart notecard reading.");
-            return DONE_READING;
-//is that the best outcome?
-        }
-        return STILL_READING;
-    } else {
-        // that's the end of the notecard.  we need some minimal verification that it
-        // wasn't full of garbage.
-        if (!found_signature_line) {
-            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
-            if (!try_next_notecard()) {
-                return BAD_NOTECARD;  // we failed to find a good line?
-            } else {
-                // the next notecard's coming through now.
-                return STILL_READING;
-            }
-        } else {
-//            if (DEBUGGING) log_it("found signature.");
-            // saw the signature line, so this is a good one.
-            return DONE_READING;
-        }
-    }
-}
-
-// only sends reply; does not reset notecard process.
-send_reply(integer destination, list parms, string command,
-    integer include_query)
-{
-//log_it("froyo: curre code=" + current_response_code);
-//integer items = llGetListLength(parms);
-//if (include_query) items += llGetListLength(global_query_contents);
-//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
-
-   if (!include_query) {
-        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-    } else {
-        handle_link_message(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command,
-            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
-    }
-    global_query_contents = [];
-//log_it("post-sending, mem=" + (string)llGetFreeMemory());
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply_and_reset(integer destination, list parms, string command,
-    integer include_query)
-{
-    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
-    send_reply(destination, parms, command, include_query);
-//log_it("about to reset response code");
-    current_response_code = 0;  // reset back to default so we can start another read.
-    global_query_id = NULL_KEY;  // reset so we accept no more data.
-}
-
-// if there are other pending notecard reads, this goes to the next one listed.
-dequeue_next_request()
-{
-    if (llGetListLength(pending_signatures)) {
-        // get the info from the next pending item.
-        string sig = llList2String(pending_signatures, 0);
-        integer response_code_temp = llList2Integer(pending_response_codes, 0);
-        string notecard = llList2String(pending_notecard_names, 0);
-        // whack the head of the queue since we grabbed the info.
-        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
-        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
-        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
-        if (llStringLength(notecard)) {
-            global_notecard_name = notecard;
-            select_specific_notecard();
-        } else {
-            reset_for_reading(sig, response_code_temp);
-        }
-    }
-}
-
-// deals with one data server answer from the notecard.
-process_notecard_line(key query_id, string data)
-{
-    // try to consume a line from the notecard.
-    integer outcome = handle_notecard_line(query_id, data);
-    if (outcome == DONE_READING) {
-        // that was a valid notecard and we read all of it.
-        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
-        // send back the results.
-        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
-            READ_NOTECARD_COMMAND, TRUE);
-    } else if (outcome == BAD_NOTECARD) {
-        // bail; this problem must be addressed by other means.
-        if (DEBUGGING) log_it("failed to find an appropriate notecard");
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    } else if (outcome == STILL_READING) {
-        // we have a good card and are still processing it.
-        return;
-    } else {
-        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
-        // again, bail out.  we have no idea what happened with this.
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    }
-    // if we have reached here, we should crank up the next queued notecard reading.
-    dequeue_next_request();
-}
-
-// processes requests from our users.
-noteworthy_handle_link_message(integer which, integer num, string msg, key id)
-{
-    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
-
-    if (msg == READ_NOTECARD_COMMAND) {
-        only_read_one_notecard = FALSE;  // general inquiry for any card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read notecard--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code_temp = llList2Integer(parms, 1);
-//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code_temp);
-            if (!try_next_notecard()) {
-                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
-                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code_temp ],
-                    READ_NOTECARD_COMMAND, FALSE);
-                return;
-            }
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code_temp;
-//holding:            pending_notecard_names += "";
-//holding:        }
-    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
-        only_read_one_notecard = TRUE;  // they want one particular card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read specific--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code_temp = llList2Integer(parms, 1);
-        string notecard_name = llList2String(parms, 2);
-//log_it("got signature " + signature + " and respcode " + (string)response_code_temp);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code_temp);
-            global_notecard_name = notecard_name;  // set our global.
-            select_specific_notecard();
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code_temp ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code_temp;
-//holding:            pending_notecard_names += notecard_name;
-//holding:        }
-    }
-}
-
-    
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();  // make sure newest addition is only version of script.
-/////not needed now        llSleep(1.0);  // snooze just a bit to let noteworthy start up?
-        startup_initialize();
-        initialize();  // start asking about the notecards.
-        setup_seating_arrangements();  // use our current defaults for sitting posn.
-    }
-
-    on_rez(integer parm) { llResetScript(); }
-
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-//            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
-            llResetScript(); 
-        }
-        if (!(change & CHANGED_LINK)) return;  // don't care.
-        if (!UNSEAT_AFTERWARDS) return;  // nothing else below is needed.
-        if (llAvatarOnSitTarget() == NULL_KEY) return;  // no one there, so ditto.
-        // now give them a bit of time to rest before dumping them.
-        llSetTimerEvent(PAUSE_BEFORE_EVICTION);
-    }
-    
-    timer() {
-        if (current_response_code != 0) {
-            llSetTimerEvent(0.0);  // stop any timer now.
-            // let the caller know this has failed out.
-            if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
-            send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-                READ_NOTECARD_COMMAND, FALSE);
-            current_response_code = 0;  // we gave up on that one.
-            dequeue_next_request();  // get next reading started if we have anything to read.
-        } else {
-            // perform short range teleport, effectively...
-            llUnSit(llAvatarOnSitTarget());  // ha, got that guy back up.
-            llSetTimerEvent(0.0);  // reset timer.
-        }
-    }
-
-    // process the response from the noteworthy library.
-    link_message(integer which, integer num, string msg, key id)
-    { handle_link_message(which, num, msg, id); }
-
-    dataserver(key query_id, string data) {
-        // make sure this data is for us.
-        if (global_query_id != query_id) return;
-        // yep, seems to be.
-        process_notecard_line(query_id, data);
-    }            
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/create_objects_v1.3.lsl b/huffware/huffotronic_updater_freebie_v5.3/create_objects_v1.3.lsl
new file mode 100755 (executable)
index 0000000..4311856
--- /dev/null
@@ -0,0 +1,176 @@
+
+// huffware script: create object, by fred huffhines.
+//
+// this script rezzes new objects from inventory every time the user clicks.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// from hufflets:
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end of hufflets.
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+    }
+
+    touch_start(integer total_number) {
+        if (llDetectedKey(0) != llGetOwner()) return;
+        if (llGetInventoryNumber(INVENTORY_OBJECT) < 1) {
+            llSay(0, "This object needs contents to rez; currently it has none.");
+            return;
+        }
+        integer i;
+        for (i = 0; i < llGetInventoryNumber(INVENTORY_OBJECT); i++) {
+            vector addition = random_vector(0.2, 2.0, TRUE);
+            // only allow a new z position that is higher than current value.
+            if (addition.z < 0.0) addition.z *= -1.0;
+            llRezObject(llGetInventoryName(INVENTORY_OBJECT, i), llGetPos() + addition, ZERO_VECTOR, ZERO_ROTATION, 0);
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/create_objects_v1.3.txt b/huffware/huffotronic_updater_freebie_v5.3/create_objects_v1.3.txt
deleted file mode 100755 (executable)
index 4311856..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-
-// huffware script: create object, by fred huffhines.
-//
-// this script rezzes new objects from inventory every time the user clicks.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// from hufflets:
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end of hufflets.
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-    }
-
-    touch_start(integer total_number) {
-        if (llDetectedKey(0) != llGetOwner()) return;
-        if (llGetInventoryNumber(INVENTORY_OBJECT) < 1) {
-            llSay(0, "This object needs contents to rez; currently it has none.");
-            return;
-        }
-        integer i;
-        for (i = 0; i < llGetInventoryNumber(INVENTORY_OBJECT); i++) {
-            vector addition = random_vector(0.2, 2.0, TRUE);
-            // only allow a new z position that is higher than current value.
-            if (addition.z < 0.0) addition.z *= -1.0;
-            llRezObject(llGetInventoryName(INVENTORY_OBJECT, i), llGetPos() + addition, ZERO_VECTOR, ZERO_ROTATION, 0);
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/data_cow_v3.3.lsl b/huffware/huffotronic_updater_freebie_v5.3/data_cow_v3.3.lsl
new file mode 100755 (executable)
index 0000000..c03cb4c
--- /dev/null
@@ -0,0 +1,227 @@
+
+// huffware script: data cow, by fred huffhines.
+//
+// a data cow is a script that manages a list of text items.  it allows an object
+// to offload the memory burden of managing a list of items, since LSL is very tight
+// on memory, even when compiled to mono.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global variables.
+
+list the_list;
+    // the main list that we manage here.  we support adding to it, retrieving it
+    // and modifying it via our API.
+list the_names;
+    // the short names for each item in our list.  we are basically supporting a
+    // symbol table data structure here.
+
+// link message API for the data cow library.
+//////////////
+// do not redefine these constants.
+integer DATA_COW_HUFFWARE_ID = 10017;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+///string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+//
+string RESET_LIST_COMMAND = "reset_L";
+    // flushes out the currently held list.  does not send a reply.
+string ADD_ITEM_COMMAND = "add_I";
+    // adds items to the list.  this is a list of pairs of name/value, where the name is
+    // how the item will be looked up from the list, and the value is the contents to be stored.
+    // this command has no reply.
+string REMOVE_ITEM_COMMAND = "rm_I";
+    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
+    // this command also has no reply.
+string GET_COW_LENGTH = "get_Lc";
+    // returns a single integer which is the length of the cow's list currently.
+string GET_ITEM_COMMAND = "get_I";
+    // retrieves the item's contents for a given name.  first parm is the name.  if there
+    // are other parameters, then they are taken as other items to return also.
+    // the return data will be pairs of <name, entry> for each of the names in the request
+    // that is not empty.  note that you can use an integer index by prefacing it with a
+    // '#' sign.  for example, asking for item "#32" will return index 32 in the list of items.
+string TAGGED_GET_ITEM_COMMAND = "get_T";
+    // like get item, except the first parameter is an identifier that the caller wants to
+    // use to tag this request.  the other parameters are still taken as names.  the response
+    // will contain the tag as the first item, then the <name, entry> pairs that were found.
+//////////////
+
+// sets up the data cow for business.
+initialize()
+{
+    // flush all contents.
+    the_list = [];
+    the_names = [];
+}
+
+// find a named item in our list, if it exists.
+integer lookup_item(string name)
+{
+    integer indy;
+    if (llGetSubString(name, 0, 0) == "#") {
+        // our special sign for just using an index.
+        indy = (integer)llGetSubString(name, 1, -1);
+        if ( (indy >= 0) && (indy < llGetListLength(the_names)) ) return indy;
+    } else {
+        for (indy = 0; indy < llGetListLength(the_names); indy++) {
+            if (name == llList2String(the_names, indy)) return indy;  // we know where it is now.
+        }
+    }
+    return -1;  // never found it.
+}
+
+// places a named item in our list.  if there's an existing item with
+// that name, then it's replaced.
+integer global_mem_complained = FALSE;
+add_item(string name, string content)
+{
+    if (llGetFreeMemory() < 2000) {
+        if (!global_mem_complained) {
+            global_mem_complained = TRUE;
+            llOwnerSay("out of memory at " + name);
+        }
+        return;
+    }
+    integer current = lookup_item(name);
+    if (current < 0) {
+//llOwnerSay("new item: " + name);
+        // this is a new item.
+        the_names += name;
+        the_list += content;
+    } else {
+//llOwnerSay("reusing slot " + (string)current + " for " + name);
+        // this is an old item to be replaced.
+        the_list = chop_list(the_list, 0, current - 1)
+            + [ content ]
+            + chop_list(the_list, current + 1, llGetListLength(the_list) - 1);
+    }
+//log_it("mem=" + (string)llGetFreeMemory());
+}
+
+// deletes an existing item if possible.  TRUE is returned on success.
+integer remove_item(string name)
+{
+    integer indy = lookup_item(name);
+    if (indy < 0) return FALSE;  // not present.
+    // found our sad whackee.  we know the name and content should be
+    // stored at the exact same index in the two lists.
+    the_names = chop_list(the_names, 0, indy - 1)
+        + chop_list(the_names, indy + 1, llGetListLength(the_names) - 1);
+    the_list = chop_list(the_list, 0, indy - 1)
+        + chop_list(the_list, indy + 1, llGetListLength(the_list) - 1);
+    return TRUE;  // all done here.
+}
+
+// supports our link message API by answering requests from clients.
+handle_link_message(integer sender, integer num, string msg, key id)
+{
+    if (num != DATA_COW_HUFFWARE_ID) return;  // not for us.
+//log_it("hlm--mem free=" + (string)llGetFreeMemory());
+//log_it("rcvd: " + msg + " " + (string)num + " " + (string)id);
+    if (msg == RESET_LIST_COMMAND) {
+        initialize();
+    } else if (msg == ADD_ITEM_COMMAND) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        integer indy;
+        for (indy = 0; indy < llGetListLength(parms); indy += 2) {
+            add_item(llList2String(parms, indy), llList2String(parms, indy + 1));
+        }
+    } else if (msg == REMOVE_ITEM_COMMAND) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        integer indy;
+        for (indy = 0; indy < llGetListLength(parms); indy++) {
+            remove_item(llList2String(parms, indy));
+        }
+    } else if (msg == GET_COW_LENGTH) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        string tag = llList2String(parms, 0);
+        list to_reply;
+        if (tag != "") to_reply = [ tag ];
+        to_reply += [ llGetListLength(the_list) ];
+        send_reply(LINK_THIS, to_reply, msg);
+    } else if ( (msg == GET_ITEM_COMMAND) || (msg == TAGGED_GET_ITEM_COMMAND) ) {
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        integer indy;
+        string tag;
+        if (msg == TAGGED_GET_ITEM_COMMAND) {
+            // extract the tag, if they want that type of command handling.
+            tag = llList2String(parms, 0);
+            parms = llDeleteSubList(parms, 0, 0);
+        }
+        list to_reply;
+        // make sure we return the tag if they gave us one.
+        if (tag != "") to_reply = [ tag ];
+        for (indy = 0; indy < llGetListLength(parms); indy++) {
+            // iterate through the parameters and reply about any that we find.
+            integer found_posn = lookup_item(llList2String(parms, indy));
+            if (found_posn >= 0) {
+                // this item did exist.
+                to_reply += [ llList2String(the_names, found_posn), llList2String(the_list, found_posn) ];
+            }
+        }
+        send_reply(LINK_THIS, to_reply, msg);
+    } 
+}
+
+//////////////
+// from hufflets...
+//
+//integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+//log_it(string to_say)
+//{
+//    debug_num++;
+//    // tell this to the owner.    
+//    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//    // say this on open chat, but use an unusual channel.
+////    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply(integer destination, list parms, string command)
+{
+    llMessageLinked(destination, DATA_COW_HUFFWARE_ID + REPLY_DISTANCE,
+        command,  llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+//
+// end hufflets
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { initialize(); }
+
+    link_message(integer sender, integer num, string msg, key id)
+    { handle_link_message(sender, num, msg, id); }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/data_cow_v3.3.txt b/huffware/huffotronic_updater_freebie_v5.3/data_cow_v3.3.txt
deleted file mode 100755 (executable)
index c03cb4c..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-
-// huffware script: data cow, by fred huffhines.
-//
-// a data cow is a script that manages a list of text items.  it allows an object
-// to offload the memory burden of managing a list of items, since LSL is very tight
-// on memory, even when compiled to mono.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global variables.
-
-list the_list;
-    // the main list that we manage here.  we support adding to it, retrieving it
-    // and modifying it via our API.
-list the_names;
-    // the short names for each item in our list.  we are basically supporting a
-    // symbol table data structure here.
-
-// link message API for the data cow library.
-//////////////
-// do not redefine these constants.
-integer DATA_COW_HUFFWARE_ID = 10017;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-///string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-//
-string RESET_LIST_COMMAND = "reset_L";
-    // flushes out the currently held list.  does not send a reply.
-string ADD_ITEM_COMMAND = "add_I";
-    // adds items to the list.  this is a list of pairs of name/value, where the name is
-    // how the item will be looked up from the list, and the value is the contents to be stored.
-    // this command has no reply.
-string REMOVE_ITEM_COMMAND = "rm_I";
-    // accepts a list of names for items.  all the mentioned ones will be removed from the list.
-    // this command also has no reply.
-string GET_COW_LENGTH = "get_Lc";
-    // returns a single integer which is the length of the cow's list currently.
-string GET_ITEM_COMMAND = "get_I";
-    // retrieves the item's contents for a given name.  first parm is the name.  if there
-    // are other parameters, then they are taken as other items to return also.
-    // the return data will be pairs of <name, entry> for each of the names in the request
-    // that is not empty.  note that you can use an integer index by prefacing it with a
-    // '#' sign.  for example, asking for item "#32" will return index 32 in the list of items.
-string TAGGED_GET_ITEM_COMMAND = "get_T";
-    // like get item, except the first parameter is an identifier that the caller wants to
-    // use to tag this request.  the other parameters are still taken as names.  the response
-    // will contain the tag as the first item, then the <name, entry> pairs that were found.
-//////////////
-
-// sets up the data cow for business.
-initialize()
-{
-    // flush all contents.
-    the_list = [];
-    the_names = [];
-}
-
-// find a named item in our list, if it exists.
-integer lookup_item(string name)
-{
-    integer indy;
-    if (llGetSubString(name, 0, 0) == "#") {
-        // our special sign for just using an index.
-        indy = (integer)llGetSubString(name, 1, -1);
-        if ( (indy >= 0) && (indy < llGetListLength(the_names)) ) return indy;
-    } else {
-        for (indy = 0; indy < llGetListLength(the_names); indy++) {
-            if (name == llList2String(the_names, indy)) return indy;  // we know where it is now.
-        }
-    }
-    return -1;  // never found it.
-}
-
-// places a named item in our list.  if there's an existing item with
-// that name, then it's replaced.
-integer global_mem_complained = FALSE;
-add_item(string name, string content)
-{
-    if (llGetFreeMemory() < 2000) {
-        if (!global_mem_complained) {
-            global_mem_complained = TRUE;
-            llOwnerSay("out of memory at " + name);
-        }
-        return;
-    }
-    integer current = lookup_item(name);
-    if (current < 0) {
-//llOwnerSay("new item: " + name);
-        // this is a new item.
-        the_names += name;
-        the_list += content;
-    } else {
-//llOwnerSay("reusing slot " + (string)current + " for " + name);
-        // this is an old item to be replaced.
-        the_list = chop_list(the_list, 0, current - 1)
-            + [ content ]
-            + chop_list(the_list, current + 1, llGetListLength(the_list) - 1);
-    }
-//log_it("mem=" + (string)llGetFreeMemory());
-}
-
-// deletes an existing item if possible.  TRUE is returned on success.
-integer remove_item(string name)
-{
-    integer indy = lookup_item(name);
-    if (indy < 0) return FALSE;  // not present.
-    // found our sad whackee.  we know the name and content should be
-    // stored at the exact same index in the two lists.
-    the_names = chop_list(the_names, 0, indy - 1)
-        + chop_list(the_names, indy + 1, llGetListLength(the_names) - 1);
-    the_list = chop_list(the_list, 0, indy - 1)
-        + chop_list(the_list, indy + 1, llGetListLength(the_list) - 1);
-    return TRUE;  // all done here.
-}
-
-// supports our link message API by answering requests from clients.
-handle_link_message(integer sender, integer num, string msg, key id)
-{
-    if (num != DATA_COW_HUFFWARE_ID) return;  // not for us.
-//log_it("hlm--mem free=" + (string)llGetFreeMemory());
-//log_it("rcvd: " + msg + " " + (string)num + " " + (string)id);
-    if (msg == RESET_LIST_COMMAND) {
-        initialize();
-    } else if (msg == ADD_ITEM_COMMAND) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        integer indy;
-        for (indy = 0; indy < llGetListLength(parms); indy += 2) {
-            add_item(llList2String(parms, indy), llList2String(parms, indy + 1));
-        }
-    } else if (msg == REMOVE_ITEM_COMMAND) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        integer indy;
-        for (indy = 0; indy < llGetListLength(parms); indy++) {
-            remove_item(llList2String(parms, indy));
-        }
-    } else if (msg == GET_COW_LENGTH) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        string tag = llList2String(parms, 0);
-        list to_reply;
-        if (tag != "") to_reply = [ tag ];
-        to_reply += [ llGetListLength(the_list) ];
-        send_reply(LINK_THIS, to_reply, msg);
-    } else if ( (msg == GET_ITEM_COMMAND) || (msg == TAGGED_GET_ITEM_COMMAND) ) {
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        integer indy;
-        string tag;
-        if (msg == TAGGED_GET_ITEM_COMMAND) {
-            // extract the tag, if they want that type of command handling.
-            tag = llList2String(parms, 0);
-            parms = llDeleteSubList(parms, 0, 0);
-        }
-        list to_reply;
-        // make sure we return the tag if they gave us one.
-        if (tag != "") to_reply = [ tag ];
-        for (indy = 0; indy < llGetListLength(parms); indy++) {
-            // iterate through the parameters and reply about any that we find.
-            integer found_posn = lookup_item(llList2String(parms, indy));
-            if (found_posn >= 0) {
-                // this item did exist.
-                to_reply += [ llList2String(the_names, found_posn), llList2String(the_list, found_posn) ];
-            }
-        }
-        send_reply(LINK_THIS, to_reply, msg);
-    } 
-}
-
-//////////////
-// from hufflets...
-//
-//integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-//log_it(string to_say)
-//{
-//    debug_num++;
-//    // tell this to the owner.    
-//    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//    // say this on open chat, but use an unusual channel.
-////    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply(integer destination, list parms, string command)
-{
-    llMessageLinked(destination, DATA_COW_HUFFWARE_ID + REPLY_DISTANCE,
-        command,  llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-//
-// end hufflets
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { initialize(); }
-
-    link_message(integer sender, integer num, string msg, key id)
-    { handle_link_message(sender, num, msg, id); }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/fade_opacity_v3.7.lsl b/huffware/huffotronic_updater_freebie_v5.3/fade_opacity_v3.7.lsl
new file mode 100755 (executable)
index 0000000..1671e5a
--- /dev/null
@@ -0,0 +1,201 @@
+
+// huffware script: fade opacity, by fred huffhines, bsd-style license.
+//
+// when the object is touched, the opacity changes towards either
+// totally transparent or totally opaque.  when touch stops, the
+// changes stop.  the next time the objects is touched, the opacity
+// changes in the opposite direction.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// modifiable parameters for the fading...
+
+integer SWITCH_ONLY = FALSE;  // if true, does not fade, just switches on and off.
+
+float pace_increment = 0.02;  // how much we change transparency in one timer call.
+
+float timer_interval = 0.1;  // how frequently timer is hit.
+
+float highest_opacity = 1.0;  // the most visible an object can be.
+
+float lowest_opacity = 0.0;  // the least visible an object can be.
+
+//integer FADE_TARGETS = LINK_THIS;  // affect only the prim this script is in.
+integer FADE_TARGETS = LINK_SET;  // fade the entire object, all prims.
+//integer FADE_TARGETS = 3;  // fade just the second prim, not the root.
+
+// globals...
+
+float global_direction = -1.0;
+    // tells us whether we are making the object more transparent
+    // (positive numbers) or less transparent (negative numbers).
+
+integer last_update;
+    // unix time of last mention of the opacity.
+
+// displays the current opaqueness of the object.
+show_opacity()
+{
+    float opacity = llGetAlpha(ALL_SIDES) / (float)llGetNumberOfSides() * 100.0;
+    string message = (string)((integer)opacity) + "% opacity";
+    llSetText(message, <.2, .8, .6>, 1.0);
+    // whisper the setting if we haven't in a bit.
+    if (llGetUnixTime() - last_update >= 2) {
+        llWhisper(0, message);
+        last_update = llGetUnixTime();
+    }
+}
+
+// get rid of the text label.
+show_nothing() { llSetText("", <0.0, 0.0, 0.0>, 0.0); }
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        show_nothing();  // clean out any existing text.
+        last_update = llGetUnixTime();
+    }
+
+    touch_start(integer total_number) {
+        global_direction *= -1.0;  // change the direction for next time.
+        if (SWITCH_ONLY) {
+            if (global_direction > 0.0)
+                llSetLinkAlpha(FADE_TARGETS, highest_opacity, ALL_SIDES);
+            else
+                llSetLinkAlpha(FADE_TARGETS, lowest_opacity, ALL_SIDES);
+        } else {
+            // do the full fade routine.  start the timer to change the
+            // opacity while the avatar keeps touching the object.
+            llSetTimerEvent(timer_interval);
+        }
+    }
+
+    touch_end(integer total_number) {
+        llSetTimerEvent(0);  // stop the timer.
+        show_nothing();  // clear the text out.
+    }
+
+    timer() {
+        float current = llGetAlpha(ALL_SIDES) / (float)llGetNumberOfSides()
+            + pace_increment * global_direction;
+        if (current > highest_opacity) { current = highest_opacity; }
+        if (current < lowest_opacity) { current = lowest_opacity; }
+        // change transparency on all links, including root prim.
+        llSetLinkAlpha(FADE_TARGETS, current, ALL_SIDES);
+        show_opacity();
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/fade_opacity_v3.7.txt b/huffware/huffotronic_updater_freebie_v5.3/fade_opacity_v3.7.txt
deleted file mode 100755 (executable)
index 1671e5a..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-
-// huffware script: fade opacity, by fred huffhines, bsd-style license.
-//
-// when the object is touched, the opacity changes towards either
-// totally transparent or totally opaque.  when touch stops, the
-// changes stop.  the next time the objects is touched, the opacity
-// changes in the opposite direction.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// modifiable parameters for the fading...
-
-integer SWITCH_ONLY = FALSE;  // if true, does not fade, just switches on and off.
-
-float pace_increment = 0.02;  // how much we change transparency in one timer call.
-
-float timer_interval = 0.1;  // how frequently timer is hit.
-
-float highest_opacity = 1.0;  // the most visible an object can be.
-
-float lowest_opacity = 0.0;  // the least visible an object can be.
-
-//integer FADE_TARGETS = LINK_THIS;  // affect only the prim this script is in.
-integer FADE_TARGETS = LINK_SET;  // fade the entire object, all prims.
-//integer FADE_TARGETS = 3;  // fade just the second prim, not the root.
-
-// globals...
-
-float global_direction = -1.0;
-    // tells us whether we are making the object more transparent
-    // (positive numbers) or less transparent (negative numbers).
-
-integer last_update;
-    // unix time of last mention of the opacity.
-
-// displays the current opaqueness of the object.
-show_opacity()
-{
-    float opacity = llGetAlpha(ALL_SIDES) / (float)llGetNumberOfSides() * 100.0;
-    string message = (string)((integer)opacity) + "% opacity";
-    llSetText(message, <.2, .8, .6>, 1.0);
-    // whisper the setting if we haven't in a bit.
-    if (llGetUnixTime() - last_update >= 2) {
-        llWhisper(0, message);
-        last_update = llGetUnixTime();
-    }
-}
-
-// get rid of the text label.
-show_nothing() { llSetText("", <0.0, 0.0, 0.0>, 0.0); }
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        show_nothing();  // clean out any existing text.
-        last_update = llGetUnixTime();
-    }
-
-    touch_start(integer total_number) {
-        global_direction *= -1.0;  // change the direction for next time.
-        if (SWITCH_ONLY) {
-            if (global_direction > 0.0)
-                llSetLinkAlpha(FADE_TARGETS, highest_opacity, ALL_SIDES);
-            else
-                llSetLinkAlpha(FADE_TARGETS, lowest_opacity, ALL_SIDES);
-        } else {
-            // do the full fade routine.  start the timer to change the
-            // opacity while the avatar keeps touching the object.
-            llSetTimerEvent(timer_interval);
-        }
-    }
-
-    touch_end(integer total_number) {
-        llSetTimerEvent(0);  // stop the timer.
-        show_nothing();  // clear the text out.
-    }
-
-    timer() {
-        float current = llGetAlpha(ALL_SIDES) / (float)llGetNumberOfSides()
-            + pace_increment * global_direction;
-        if (current > highest_opacity) { current = highest_opacity; }
-        if (current < lowest_opacity) { current = lowest_opacity; }
-        // change transparency on all links, including root prim.
-        llSetLinkAlpha(FADE_TARGETS, current, ALL_SIDES);
-        show_opacity();
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_no_rot_v3.0.lsl b/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_no_rot_v3.0.lsl
new file mode 100755 (executable)
index 0000000..ca48191
--- /dev/null
@@ -0,0 +1,669 @@
+
+// huffware script: fredboxmux (no rotation), by fred huffhines.
+//
+// a memory saving kludge script; it is the combination of the canonical huffware
+// scripts: (1) non-script giver, (2) rotanium rotato, (3) text label.
+// our theory is that by having only two scripts per display object (this script and
+// the updater client) instead of four, we'll save some cpu on our overburdened but
+// beloved server (serene).
+// given that this script is intended to replace those three scripts, it will eat them
+// on startup to avoid having redundant services in the object.
+// update for april 24 2011: added a question menu before doing the copying to user's
+// inventory, since opensim can do a weird thing that sets all folders to "loading...".
+// this now keeps the objects from being super annoying when one didn't mean to click it.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// non-script giver:
+//
+// gives all objects, notecards, etc contained in an object when that object is touched.
+// does not give out scripts, since these are generally not something that should be handed
+// to the customer.
+//
+// rotanium rotato:
+//
+// causes the object to rotate according to the parameters set below.
+// this can use herky-jerky timed rotation with llSetRot or it can use
+// smooth rotation with llTargetOmega.
+//
+// text label:
+//
+// a super simple script for giving an object readable text.
+
+integer DEBUGGING = FALSE;  // set to true for noisier runs.
+
+integer DO_ROTATION = FALSE;  // is this the rotating version or not?
+
+integer USE_SENSORS = TRUE;  // should we look for avatars so we can display the label?
+
+float SMOOTH_TIMER_FREQUENCY = 7.0;
+    // fastest possible rate of change for the smooth rotater, in seconds.  the smooth
+    // rotater doesn't need to hit the timer all that often, but this is faster than it
+    // needs to be for rotation, since it is also used as the rate at which the avatar sensor
+    // fires.
+
+float TIME_TO_CLEAR_TITLE = 8.0;
+    // how many seconds before the title that was set for an avatar or due to a touch will
+    // disappear again.
+
+vector LABEL_COLOR = <0.3, 0.9, 0.4>;
+    // color of the text above object.
+
+float ACTIVE_LABEL_DISTANCE = 5.0;
+    // how far away can avatars cause the label to light up?
+
+integer ONLY_GIVE_TO_OWNER = TRUE;
+    // if this is true, then only the owner will receive a copy of the items.
+
+integer GIVE_UNCOPYABLES = FALSE;
+    // this flag is dangerous when true, because it means that uncopyable objects will still
+    // be handed to the target.  if that target refuses the non-copyable items, then the items
+    // will be lost forever.  that is not so good if you've sold the person a non-copy item.
+
+string EXCLUDED_NOTECARD = "product description";
+    // a special case; if there is a giftorse configuration card, we won't hand that out.
+
+float SMOOTH_CHANCE_FOR_ADJUSTING = 0.28;
+    // we won't always change the smooth rotation, even though our timer is pretty slow.
+    // this value is the percentage of the time that we do actually change rotation (divided
+    // by 100).
+
+float SMOOTH_ROTATION_GAIN_MAX = 0.0490873852122;
+    // the gain is how fast we will rotate in radians per second.
+    // PI / 2 is about 90 degrees per second, which seems way too fast.
+    // 0.196349540849 is about PI / 16, 0.0981747704244 is about PI / 32,
+    // and 0.0490873852122 is about PI / 64.
+
+string object_label = "default";  // change this if you want a specific name.
+
+string old_name;  // tracks the last known name so we know if we need to update title.
+float old_opacity = 3.14;  // tracks the last opacity setting for the label.
+
+integer label_changed = TRUE;
+    // this remembers if the label has stayed put or not.  we use it to decide
+    // whether we need to check the label for carriage returns.
+
+vector current_add_in = <0.0, 0.0, 0.4>;
+    // randomly assigned to if RANDOMIZE_ROTATION is true.
+
+float current_gain = -0.05;
+    // speed of smooth rotation; will randomly change if RANDOMIZE_ROTATION is true.
+
+float MIN_ADDITION = 0.01;
+    // smallest amount of change we will ever have.
+float MAX_ADDITION = 7.0;
+    // largest amount of change we will ever have.
+
+key first_toucher;  // tracks who clicked on the object to get contents.
+
+float label_opacity = 1.0;  // how opaque should text be?  1.0 is solid, 0.0 transparent.
+
+// takes out the 3 scripts that have been combined into the mux.  otherwise, it's
+// more of a pain to update all the boxes with this thing when it's ready to go.
+remove_redundant_scripts()
+{
+    integer posn;
+    string self = llGetScriptName();
+    // zoom across the scripts to see if we have any in the inventory that
+    // are slated for removal.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if (curr_script != self) {
+            if ( (llSubStringIndex(curr_script, "non-script giver") == 0)
+                || (llSubStringIndex(curr_script, "rotanium rotato") == 0)
+                || (llSubStringIndex(curr_script, "text label") == 0) ) {
+                // this one is a match!  zap it.
+                llRemoveInventory(curr_script);
+            }
+            
+        }
+    }
+}
+
+// the avatar has said it's okay to hand out all the stuff to her/him.
+really_give_contents() { give_out_contents(first_toucher); }
+
+// give out pictures, notecards, objects, etc. that are hiding in the object.
+give_out_contents(key give_to)
+{
+    list all_to_give = [];  // the set we will hand over in a batch.
+    list uncopyables = [];  // the list we have to do individually.
+    // find out how many items there are.
+    integer count = llGetInventoryNumber(INVENTORY_ALL);
+    // iterate across all the items and add them to the gift list if appropriate.
+    integer indy;
+    for (indy = 0; indy < count; indy++) {
+        string item_name = llGetInventoryName(INVENTORY_ALL, indy);
+        integer type = llGetInventoryType(item_name);
+        if ( (type != INVENTORY_SCRIPT) 
+            && ( (type != INVENTORY_NOTECARD) || (item_name != EXCLUDED_NOTECARD) ) ) {
+            // it's okay to add this item; it's not a script and we are not skipping the special notecard.
+            integer mask = MASK_OWNER;
+            if (!ONLY_GIVE_TO_OWNER) mask = MASK_EVERYONE;
+            integer perms = llGetInventoryPermMask(item_name, mask);
+            if (perms & PERM_COPY) {
+                // a normal object that we can hand out.
+                all_to_give += item_name;
+            } else {
+                uncopyables += item_name;
+            }
+        }
+    }
+    // hand the customer the whole set as one big chunk, named after the object.
+    llGiveInventoryList(give_to, llGetObjectName(), all_to_give);
+
+    // handle any problematic items.  we cannot copy these objects into a category folder,
+    // so we can either not try to copy them (a lot safer) or we can try to deliver them
+    // normally as individual items.  the latter choice is more dangerous, because if the
+    // owner discards these items rather than keeping them, the items will be lost forever!
+    if (llGetListLength(uncopyables) > 0) {
+        string plural = " ";
+        string is_verb = "is ";
+        string third_noun_subj = "it ";
+        string third_noun_obj = "it ";
+        if (llGetListLength(uncopyables) > 1) {
+            plural = "s ";
+            is_verb = "are ";
+            third_noun_subj = "they ";
+            third_noun_obj = "them ";
+        }
+        
+        string uncopyable_message = "will be left inside the object.  To get " + third_noun_obj
+            + ", please copy " + third_noun_obj + "\nmanually from this object into your inventory.";
+        if (GIVE_UNCOPYABLES) {
+            uncopyable_message = "will be moved over to your inventory."
+            + "\nPlease look in your main folders for "
+            + third_noun_obj + "(e.g., in Objects or Textures).";
+        }
+        
+        string failure_message = "The item" + plural
+            + "[" + llDumpList2String(uncopyables, "; ") + "]\n"
+            + is_verb + "not copyable; " + third_noun_subj
+            + uncopyable_message;
+            
+        if (llGetOwner() == give_to) {
+            // the object can be moved to inventory, but not with the category method.
+            llOwnerSay(failure_message);
+        } else {
+            // this seems like a weird case; it will probably just fail anyhow?
+            // if the item's not copyable and you're not the owner of this object,
+            // how can we give it to you?
+            llInstantMessage(give_to, failure_message);
+        }
+        
+        // now that we've announced this weird situation, handle it appropriately.
+        if (GIVE_UNCOPYABLES) {
+            for (indy = 0; indy < llGetListLength(uncopyables); indy++) {
+                string item_name = llList2String(uncopyables, indy);
+                llGiveInventory(give_to, item_name);
+            }
+        }  // otherwise leave them be.
+    }
+}
+
+// causes the object to rotate using whatever the current settings are.
+smooth_rotate_using_our_settings()
+{
+    // make sure we are using the rotational values we were asked to.
+    llTargetOmega(current_add_in, current_gain, 1.0);
+}
+
+// sets the gain and add in to random choices.
+randomize_values()
+{
+    current_gain = randomize_within_range(0.001, SMOOTH_ROTATION_GAIN_MAX, TRUE);
+    current_add_in = random_vector(MIN_ADDITION, MAX_ADDITION, TRUE);
+}
+
+// performs the timed rotation that has been configured for us.
+rotate_as_requested()
+{
+    // our slack timer went off, so randomize the rotation if requested.
+    if (llFrand(1.0) >= (1.0 - SMOOTH_CHANCE_FOR_ADJUSTING) ) {
+        randomize_values();
+        smooth_rotate_using_our_settings();
+    }
+}
+
+initialize_fredboxmux()
+{
+    // make sure we pick a good random channel.
+    menu_system_channel = -1 * (integer)randomize_within_range(200, 10000000, FALSE);
+
+    // if needed, we will set our initial random rotation.
+    randomize_values();
+        
+    // do a first rotate, so we move right at startup.  otherwise we won't move
+    // until after our first timer hits.
+    if (DO_ROTATION) rotate_as_requested();
+
+    // now set the timer for our mode.
+    llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
+    if (DO_ROTATION) smooth_rotate_using_our_settings();
+}
+
+set_text()
+{
+//log_it("old name " + old_name + " -- curr name " + llGetObjectName());
+    if (old_name != llGetObjectName()) {
+        // we're out of synch on the object name.
+        label_changed = TRUE;
+    }
+    if (old_opacity != label_opacity) {
+        // here we're out of synch on last opacity used.
+        label_changed = TRUE;
+    }
+    if (label_changed) {
+        // reset the object title to a decorated version of object name if it says "default".
+        string new_label = object_label;
+        if (new_label == "default") new_label = llGetObjectName();
+    
+        integer indy;
+        integer keep_going = TRUE;
+        while (keep_going) {
+            indy = find_substring(new_label, "\\n");
+            if (indy < 0) {
+                keep_going = FALSE;
+            } else {
+                new_label = llGetSubString(new_label, 0, indy - 1)
+                    + "\n" + llGetSubString(new_label, indy + 2, -1);
+            }
+        }
+        old_name = llGetObjectName();
+        old_opacity = label_opacity;
+        label_changed = FALSE;  // we have dealt with it now.
+//log_it("setting text: " + new_label);
+        llSetText(new_label, LABEL_COLOR, label_opacity);
+    }
+    if (label_opacity != 0) {
+        // if we set a lit-up title, clear it again pretty soon.
+        llSetTimerEvent(TIME_TO_CLEAR_TITLE);
+    }
+}
+
+//////////////
+// code borrowed from menutini to raise a menu asking if they actually meant to get all
+// the contents.  an opensim inventory bug makes all the folders look foolish if we
+// do any inventory giving accidentally.
+//////////////
+
+// global variables...
+
+list _private_global_buttons;  // holds onto the active set of menu options.
+string _private_global_av_key;  // the key for the avatar who clicks the menu.
+string _private_global_title;  // holds onto current title text.
+
+integer _menu_base_start = 0;  // position in the items of the current menu.
+
+integer listening_id = 0;
+    // the current id of our listening for the menu.  it's an id returned by LSL
+    // that we need to track so we can cancel the listen.
+
+integer menu_system_channel = -123;
+    // messages come back to us from this channel when user clicks the dialog.
+    // this is set later and the default is meaningless.
+
+string global_menu_name = "";
+    // hangs onto the current menu's name.
+
+//hmmm: note; to manage multiple concurrent menus on different channels,
+//      we must make these into lists.  then the timeouts should apply
+//      individually to these instead of overall (if we even do timeouts;
+//      it's nicer if menus never stop being active).
+
+string NEXT_MENU_TEXT = "Next >>";
+    // what the next item will say for showing next menu page.
+    
+//integer TIMEOUT_FOR_MENU = 42;
+    // timeout for the menu in seconds.
+
+// displays the menu requested.  it's "menu_name" is an internal name that is
+// not displayed to the user.  the "title" is the content shown in the main area
+// of the menu.  "commands_in" is the list of menu items to show as buttons.
+// the "menu_channel" is where the user's clicked response will be sent.  the
+// "listen_to" key is the avatar expected to click the menu, which is needed to
+// listen to his response.
+show_menu(string menu_name, string title, list buttons,
+    integer menu_channel, key listen_to)
+{
+    // save our new parms.
+    global_menu_name = menu_name;
+    _private_global_title = title;
+    _private_global_buttons = buttons;
+    menu_system_channel = menu_channel;
+    _private_global_av_key = listen_to;
+    if (DEBUGGING) {
+        log_it("menu name: " + global_menu_name);
+        log_it("title: " + _private_global_title);
+        log_it("buttons: " + (string)buttons);
+        log_it("channel: " + (string)menu_system_channel);
+        log_it("listen key: " + (string)listen_to);
+    }
+
+    integer add_next = FALSE;  // true if we should add a next menu item.
+
+    // the math here incorporates current button position.
+    integer current = _menu_base_start;
+    integer max_buttons = llGetListLength(buttons) - current;
+
+    if (max_buttons > 12) {
+        // limitation of SL: menus have a max of 12 buttons.
+        max_buttons = 12;
+        add_next = TRUE;
+    } else if (llGetListLength(buttons) > 12) {
+        // we already have been adding next.  let's make sure this gets
+        // a wrap-around next button.
+        add_next = TRUE;
+    }
+    // chop out what we can use in a menu.
+    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
+    if (add_next) {
+        // we were asked to add a menu item for the next screen.
+        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
+    }
+
+    listening_id = llListen(menu_channel, "", listen_to, "");
+    list commands;
+    integer i;
+    // take only the prefix of the string, to avoid getting a length complaint.
+    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
+        string curr = llList2String(trunc_buttons, i);
+        integer last_pos = 23;  // default maximum, highest possible is 24.
+        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
+        curr = llGetSubString(curr, 0, last_pos);
+        commands += curr;
+    }
+    llDialog(listen_to, title, commands, menu_channel);
+}
+
+// shuts down any connection we might have had with any active menu.  we will not
+// send any responses after this point (although we might already have responded when
+// the user clicked the menu).
+clear_menu()
+{
+    llListenRemove(listening_id);
+}
+
+// process the response when the user chooses a menu item.
+process_menu_response(integer channel, string name, key id, string message)
+{
+  if (channel != menu_system_channel) return;  // not for us.
+  
+    if (message == NEXT_MENU_TEXT) {
+        // this is the special choice, so we need to go to the next page.
+        _menu_base_start += 11;
+        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
+            // we have wrapped around the list.  go to the start again.
+            _menu_base_start = 0;
+        }
+        show_menu(global_menu_name, _private_global_title,
+            _private_global_buttons, menu_system_channel,
+            _private_global_av_key);
+        return;  // handled by opening a new menu.
+    }
+    
+    string calculated_name;
+    integer indy;
+    // first try for an exact match.
+    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+        string curr = llList2String(_private_global_buttons, indy);
+        if (curr == message) {
+            // correct the answer based on the full button string.
+            calculated_name = curr;
+        }
+    }
+    if (calculated_name == "") {
+        // try an imprecise match if the exact matching didn't work.
+        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+            string curr = llList2String(_private_global_buttons, indy);
+            if (is_prefix(curr, message)) {
+                // correct the answer based on the full button string.
+                calculated_name = curr;
+            }
+        }
+    }
+    if (calculated_name == "yes") {
+        // only send a response if that menu choice made sense to us.
+        really_give_contents();
+        clear_menu();
+    }
+}
+
+// end from menutini.
+//////////////
+
+//////////////
+// start of hufflets...
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+//////////////
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//end hufflets...
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        remove_redundant_scripts();
+        initialize_fredboxmux();
+        label_opacity = 1;  // start out showing the label.
+        set_text();
+    }
+    
+    on_rez(integer start_parm) { state default; }
+    
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            // we show the label at least a bit when the contents change.
+            label_opacity = 1;
+            set_text(); 
+        }
+    }
+    
+    touch_start(integer num) {
+        label_opacity = 1.0;
+        set_text();
+        first_toucher = llDetectedKey(0);
+        // are we only supposed to give stuff to the owner?
+        if (ONLY_GIVE_TO_OWNER && (first_toucher != llGetOwner()) ) {
+            first_toucher = NULL_KEY;
+            return;  // bail out.
+        }
+        show_menu("askreally", "Would you like a copy of this object's contents?",
+            ["yes", "no"], -18264, first_toucher);
+    }
+
+    listen(integer channel, string name, key id, string message)
+    { process_menu_response(channel, name, id, message); }
+
+    timer() {
+        llSetTimerEvent(0);
+        if (DO_ROTATION) rotate_as_requested();
+        if (USE_SENSORS) {
+            llSensor("", NULL_KEY, AGENT, ACTIVE_LABEL_DISTANCE, PI);
+        } else {
+            if (label_opacity != 0.0) {
+                label_opacity = 0.0;
+                set_text();
+            }            
+        }
+        llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
+    }
+
+    sensor(integer count) {
+        if (label_opacity != 1.0) {
+            label_opacity = 1.0;
+            set_text();
+        }
+    }
+    
+    no_sensor() {
+        if (label_opacity != 0.0) {
+            label_opacity = 0.0;
+            set_text();
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_no_rot_v3.0.txt b/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_no_rot_v3.0.txt
deleted file mode 100755 (executable)
index ca48191..0000000
+++ /dev/null
@@ -1,669 +0,0 @@
-
-// huffware script: fredboxmux (no rotation), by fred huffhines.
-//
-// a memory saving kludge script; it is the combination of the canonical huffware
-// scripts: (1) non-script giver, (2) rotanium rotato, (3) text label.
-// our theory is that by having only two scripts per display object (this script and
-// the updater client) instead of four, we'll save some cpu on our overburdened but
-// beloved server (serene).
-// given that this script is intended to replace those three scripts, it will eat them
-// on startup to avoid having redundant services in the object.
-// update for april 24 2011: added a question menu before doing the copying to user's
-// inventory, since opensim can do a weird thing that sets all folders to "loading...".
-// this now keeps the objects from being super annoying when one didn't mean to click it.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// non-script giver:
-//
-// gives all objects, notecards, etc contained in an object when that object is touched.
-// does not give out scripts, since these are generally not something that should be handed
-// to the customer.
-//
-// rotanium rotato:
-//
-// causes the object to rotate according to the parameters set below.
-// this can use herky-jerky timed rotation with llSetRot or it can use
-// smooth rotation with llTargetOmega.
-//
-// text label:
-//
-// a super simple script for giving an object readable text.
-
-integer DEBUGGING = FALSE;  // set to true for noisier runs.
-
-integer DO_ROTATION = FALSE;  // is this the rotating version or not?
-
-integer USE_SENSORS = TRUE;  // should we look for avatars so we can display the label?
-
-float SMOOTH_TIMER_FREQUENCY = 7.0;
-    // fastest possible rate of change for the smooth rotater, in seconds.  the smooth
-    // rotater doesn't need to hit the timer all that often, but this is faster than it
-    // needs to be for rotation, since it is also used as the rate at which the avatar sensor
-    // fires.
-
-float TIME_TO_CLEAR_TITLE = 8.0;
-    // how many seconds before the title that was set for an avatar or due to a touch will
-    // disappear again.
-
-vector LABEL_COLOR = <0.3, 0.9, 0.4>;
-    // color of the text above object.
-
-float ACTIVE_LABEL_DISTANCE = 5.0;
-    // how far away can avatars cause the label to light up?
-
-integer ONLY_GIVE_TO_OWNER = TRUE;
-    // if this is true, then only the owner will receive a copy of the items.
-
-integer GIVE_UNCOPYABLES = FALSE;
-    // this flag is dangerous when true, because it means that uncopyable objects will still
-    // be handed to the target.  if that target refuses the non-copyable items, then the items
-    // will be lost forever.  that is not so good if you've sold the person a non-copy item.
-
-string EXCLUDED_NOTECARD = "product description";
-    // a special case; if there is a giftorse configuration card, we won't hand that out.
-
-float SMOOTH_CHANCE_FOR_ADJUSTING = 0.28;
-    // we won't always change the smooth rotation, even though our timer is pretty slow.
-    // this value is the percentage of the time that we do actually change rotation (divided
-    // by 100).
-
-float SMOOTH_ROTATION_GAIN_MAX = 0.0490873852122;
-    // the gain is how fast we will rotate in radians per second.
-    // PI / 2 is about 90 degrees per second, which seems way too fast.
-    // 0.196349540849 is about PI / 16, 0.0981747704244 is about PI / 32,
-    // and 0.0490873852122 is about PI / 64.
-
-string object_label = "default";  // change this if you want a specific name.
-
-string old_name;  // tracks the last known name so we know if we need to update title.
-float old_opacity = 3.14;  // tracks the last opacity setting for the label.
-
-integer label_changed = TRUE;
-    // this remembers if the label has stayed put or not.  we use it to decide
-    // whether we need to check the label for carriage returns.
-
-vector current_add_in = <0.0, 0.0, 0.4>;
-    // randomly assigned to if RANDOMIZE_ROTATION is true.
-
-float current_gain = -0.05;
-    // speed of smooth rotation; will randomly change if RANDOMIZE_ROTATION is true.
-
-float MIN_ADDITION = 0.01;
-    // smallest amount of change we will ever have.
-float MAX_ADDITION = 7.0;
-    // largest amount of change we will ever have.
-
-key first_toucher;  // tracks who clicked on the object to get contents.
-
-float label_opacity = 1.0;  // how opaque should text be?  1.0 is solid, 0.0 transparent.
-
-// takes out the 3 scripts that have been combined into the mux.  otherwise, it's
-// more of a pain to update all the boxes with this thing when it's ready to go.
-remove_redundant_scripts()
-{
-    integer posn;
-    string self = llGetScriptName();
-    // zoom across the scripts to see if we have any in the inventory that
-    // are slated for removal.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if (curr_script != self) {
-            if ( (llSubStringIndex(curr_script, "non-script giver") == 0)
-                || (llSubStringIndex(curr_script, "rotanium rotato") == 0)
-                || (llSubStringIndex(curr_script, "text label") == 0) ) {
-                // this one is a match!  zap it.
-                llRemoveInventory(curr_script);
-            }
-            
-        }
-    }
-}
-
-// the avatar has said it's okay to hand out all the stuff to her/him.
-really_give_contents() { give_out_contents(first_toucher); }
-
-// give out pictures, notecards, objects, etc. that are hiding in the object.
-give_out_contents(key give_to)
-{
-    list all_to_give = [];  // the set we will hand over in a batch.
-    list uncopyables = [];  // the list we have to do individually.
-    // find out how many items there are.
-    integer count = llGetInventoryNumber(INVENTORY_ALL);
-    // iterate across all the items and add them to the gift list if appropriate.
-    integer indy;
-    for (indy = 0; indy < count; indy++) {
-        string item_name = llGetInventoryName(INVENTORY_ALL, indy);
-        integer type = llGetInventoryType(item_name);
-        if ( (type != INVENTORY_SCRIPT) 
-            && ( (type != INVENTORY_NOTECARD) || (item_name != EXCLUDED_NOTECARD) ) ) {
-            // it's okay to add this item; it's not a script and we are not skipping the special notecard.
-            integer mask = MASK_OWNER;
-            if (!ONLY_GIVE_TO_OWNER) mask = MASK_EVERYONE;
-            integer perms = llGetInventoryPermMask(item_name, mask);
-            if (perms & PERM_COPY) {
-                // a normal object that we can hand out.
-                all_to_give += item_name;
-            } else {
-                uncopyables += item_name;
-            }
-        }
-    }
-    // hand the customer the whole set as one big chunk, named after the object.
-    llGiveInventoryList(give_to, llGetObjectName(), all_to_give);
-
-    // handle any problematic items.  we cannot copy these objects into a category folder,
-    // so we can either not try to copy them (a lot safer) or we can try to deliver them
-    // normally as individual items.  the latter choice is more dangerous, because if the
-    // owner discards these items rather than keeping them, the items will be lost forever!
-    if (llGetListLength(uncopyables) > 0) {
-        string plural = " ";
-        string is_verb = "is ";
-        string third_noun_subj = "it ";
-        string third_noun_obj = "it ";
-        if (llGetListLength(uncopyables) > 1) {
-            plural = "s ";
-            is_verb = "are ";
-            third_noun_subj = "they ";
-            third_noun_obj = "them ";
-        }
-        
-        string uncopyable_message = "will be left inside the object.  To get " + third_noun_obj
-            + ", please copy " + third_noun_obj + "\nmanually from this object into your inventory.";
-        if (GIVE_UNCOPYABLES) {
-            uncopyable_message = "will be moved over to your inventory."
-            + "\nPlease look in your main folders for "
-            + third_noun_obj + "(e.g., in Objects or Textures).";
-        }
-        
-        string failure_message = "The item" + plural
-            + "[" + llDumpList2String(uncopyables, "; ") + "]\n"
-            + is_verb + "not copyable; " + third_noun_subj
-            + uncopyable_message;
-            
-        if (llGetOwner() == give_to) {
-            // the object can be moved to inventory, but not with the category method.
-            llOwnerSay(failure_message);
-        } else {
-            // this seems like a weird case; it will probably just fail anyhow?
-            // if the item's not copyable and you're not the owner of this object,
-            // how can we give it to you?
-            llInstantMessage(give_to, failure_message);
-        }
-        
-        // now that we've announced this weird situation, handle it appropriately.
-        if (GIVE_UNCOPYABLES) {
-            for (indy = 0; indy < llGetListLength(uncopyables); indy++) {
-                string item_name = llList2String(uncopyables, indy);
-                llGiveInventory(give_to, item_name);
-            }
-        }  // otherwise leave them be.
-    }
-}
-
-// causes the object to rotate using whatever the current settings are.
-smooth_rotate_using_our_settings()
-{
-    // make sure we are using the rotational values we were asked to.
-    llTargetOmega(current_add_in, current_gain, 1.0);
-}
-
-// sets the gain and add in to random choices.
-randomize_values()
-{
-    current_gain = randomize_within_range(0.001, SMOOTH_ROTATION_GAIN_MAX, TRUE);
-    current_add_in = random_vector(MIN_ADDITION, MAX_ADDITION, TRUE);
-}
-
-// performs the timed rotation that has been configured for us.
-rotate_as_requested()
-{
-    // our slack timer went off, so randomize the rotation if requested.
-    if (llFrand(1.0) >= (1.0 - SMOOTH_CHANCE_FOR_ADJUSTING) ) {
-        randomize_values();
-        smooth_rotate_using_our_settings();
-    }
-}
-
-initialize_fredboxmux()
-{
-    // make sure we pick a good random channel.
-    menu_system_channel = -1 * (integer)randomize_within_range(200, 10000000, FALSE);
-
-    // if needed, we will set our initial random rotation.
-    randomize_values();
-        
-    // do a first rotate, so we move right at startup.  otherwise we won't move
-    // until after our first timer hits.
-    if (DO_ROTATION) rotate_as_requested();
-
-    // now set the timer for our mode.
-    llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
-    if (DO_ROTATION) smooth_rotate_using_our_settings();
-}
-
-set_text()
-{
-//log_it("old name " + old_name + " -- curr name " + llGetObjectName());
-    if (old_name != llGetObjectName()) {
-        // we're out of synch on the object name.
-        label_changed = TRUE;
-    }
-    if (old_opacity != label_opacity) {
-        // here we're out of synch on last opacity used.
-        label_changed = TRUE;
-    }
-    if (label_changed) {
-        // reset the object title to a decorated version of object name if it says "default".
-        string new_label = object_label;
-        if (new_label == "default") new_label = llGetObjectName();
-    
-        integer indy;
-        integer keep_going = TRUE;
-        while (keep_going) {
-            indy = find_substring(new_label, "\\n");
-            if (indy < 0) {
-                keep_going = FALSE;
-            } else {
-                new_label = llGetSubString(new_label, 0, indy - 1)
-                    + "\n" + llGetSubString(new_label, indy + 2, -1);
-            }
-        }
-        old_name = llGetObjectName();
-        old_opacity = label_opacity;
-        label_changed = FALSE;  // we have dealt with it now.
-//log_it("setting text: " + new_label);
-        llSetText(new_label, LABEL_COLOR, label_opacity);
-    }
-    if (label_opacity != 0) {
-        // if we set a lit-up title, clear it again pretty soon.
-        llSetTimerEvent(TIME_TO_CLEAR_TITLE);
-    }
-}
-
-//////////////
-// code borrowed from menutini to raise a menu asking if they actually meant to get all
-// the contents.  an opensim inventory bug makes all the folders look foolish if we
-// do any inventory giving accidentally.
-//////////////
-
-// global variables...
-
-list _private_global_buttons;  // holds onto the active set of menu options.
-string _private_global_av_key;  // the key for the avatar who clicks the menu.
-string _private_global_title;  // holds onto current title text.
-
-integer _menu_base_start = 0;  // position in the items of the current menu.
-
-integer listening_id = 0;
-    // the current id of our listening for the menu.  it's an id returned by LSL
-    // that we need to track so we can cancel the listen.
-
-integer menu_system_channel = -123;
-    // messages come back to us from this channel when user clicks the dialog.
-    // this is set later and the default is meaningless.
-
-string global_menu_name = "";
-    // hangs onto the current menu's name.
-
-//hmmm: note; to manage multiple concurrent menus on different channels,
-//      we must make these into lists.  then the timeouts should apply
-//      individually to these instead of overall (if we even do timeouts;
-//      it's nicer if menus never stop being active).
-
-string NEXT_MENU_TEXT = "Next >>";
-    // what the next item will say for showing next menu page.
-    
-//integer TIMEOUT_FOR_MENU = 42;
-    // timeout for the menu in seconds.
-
-// displays the menu requested.  it's "menu_name" is an internal name that is
-// not displayed to the user.  the "title" is the content shown in the main area
-// of the menu.  "commands_in" is the list of menu items to show as buttons.
-// the "menu_channel" is where the user's clicked response will be sent.  the
-// "listen_to" key is the avatar expected to click the menu, which is needed to
-// listen to his response.
-show_menu(string menu_name, string title, list buttons,
-    integer menu_channel, key listen_to)
-{
-    // save our new parms.
-    global_menu_name = menu_name;
-    _private_global_title = title;
-    _private_global_buttons = buttons;
-    menu_system_channel = menu_channel;
-    _private_global_av_key = listen_to;
-    if (DEBUGGING) {
-        log_it("menu name: " + global_menu_name);
-        log_it("title: " + _private_global_title);
-        log_it("buttons: " + (string)buttons);
-        log_it("channel: " + (string)menu_system_channel);
-        log_it("listen key: " + (string)listen_to);
-    }
-
-    integer add_next = FALSE;  // true if we should add a next menu item.
-
-    // the math here incorporates current button position.
-    integer current = _menu_base_start;
-    integer max_buttons = llGetListLength(buttons) - current;
-
-    if (max_buttons > 12) {
-        // limitation of SL: menus have a max of 12 buttons.
-        max_buttons = 12;
-        add_next = TRUE;
-    } else if (llGetListLength(buttons) > 12) {
-        // we already have been adding next.  let's make sure this gets
-        // a wrap-around next button.
-        add_next = TRUE;
-    }
-    // chop out what we can use in a menu.
-    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
-    if (add_next) {
-        // we were asked to add a menu item for the next screen.
-        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
-    }
-
-    listening_id = llListen(menu_channel, "", listen_to, "");
-    list commands;
-    integer i;
-    // take only the prefix of the string, to avoid getting a length complaint.
-    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
-        string curr = llList2String(trunc_buttons, i);
-        integer last_pos = 23;  // default maximum, highest possible is 24.
-        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
-        curr = llGetSubString(curr, 0, last_pos);
-        commands += curr;
-    }
-    llDialog(listen_to, title, commands, menu_channel);
-}
-
-// shuts down any connection we might have had with any active menu.  we will not
-// send any responses after this point (although we might already have responded when
-// the user clicked the menu).
-clear_menu()
-{
-    llListenRemove(listening_id);
-}
-
-// process the response when the user chooses a menu item.
-process_menu_response(integer channel, string name, key id, string message)
-{
-  if (channel != menu_system_channel) return;  // not for us.
-  
-    if (message == NEXT_MENU_TEXT) {
-        // this is the special choice, so we need to go to the next page.
-        _menu_base_start += 11;
-        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
-            // we have wrapped around the list.  go to the start again.
-            _menu_base_start = 0;
-        }
-        show_menu(global_menu_name, _private_global_title,
-            _private_global_buttons, menu_system_channel,
-            _private_global_av_key);
-        return;  // handled by opening a new menu.
-    }
-    
-    string calculated_name;
-    integer indy;
-    // first try for an exact match.
-    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-        string curr = llList2String(_private_global_buttons, indy);
-        if (curr == message) {
-            // correct the answer based on the full button string.
-            calculated_name = curr;
-        }
-    }
-    if (calculated_name == "") {
-        // try an imprecise match if the exact matching didn't work.
-        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-            string curr = llList2String(_private_global_buttons, indy);
-            if (is_prefix(curr, message)) {
-                // correct the answer based on the full button string.
-                calculated_name = curr;
-            }
-        }
-    }
-    if (calculated_name == "yes") {
-        // only send a response if that menu choice made sense to us.
-        really_give_contents();
-        clear_menu();
-    }
-}
-
-// end from menutini.
-//////////////
-
-//////////////
-// start of hufflets...
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-//////////////
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//end hufflets...
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        remove_redundant_scripts();
-        initialize_fredboxmux();
-        label_opacity = 1;  // start out showing the label.
-        set_text();
-    }
-    
-    on_rez(integer start_parm) { state default; }
-    
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            // we show the label at least a bit when the contents change.
-            label_opacity = 1;
-            set_text(); 
-        }
-    }
-    
-    touch_start(integer num) {
-        label_opacity = 1.0;
-        set_text();
-        first_toucher = llDetectedKey(0);
-        // are we only supposed to give stuff to the owner?
-        if (ONLY_GIVE_TO_OWNER && (first_toucher != llGetOwner()) ) {
-            first_toucher = NULL_KEY;
-            return;  // bail out.
-        }
-        show_menu("askreally", "Would you like a copy of this object's contents?",
-            ["yes", "no"], -18264, first_toucher);
-    }
-
-    listen(integer channel, string name, key id, string message)
-    { process_menu_response(channel, name, id, message); }
-
-    timer() {
-        llSetTimerEvent(0);
-        if (DO_ROTATION) rotate_as_requested();
-        if (USE_SENSORS) {
-            llSensor("", NULL_KEY, AGENT, ACTIVE_LABEL_DISTANCE, PI);
-        } else {
-            if (label_opacity != 0.0) {
-                label_opacity = 0.0;
-                set_text();
-            }            
-        }
-        llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
-    }
-
-    sensor(integer count) {
-        if (label_opacity != 1.0) {
-            label_opacity = 1.0;
-            set_text();
-        }
-    }
-    
-    no_sensor() {
-        if (label_opacity != 0.0) {
-            label_opacity = 0.0;
-            set_text();
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_v3.0.lsl b/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_v3.0.lsl
new file mode 100755 (executable)
index 0000000..c41662c
--- /dev/null
@@ -0,0 +1,669 @@
+
+// huffware script: fredboxmux (with rotation), by fred huffhines.
+//
+// a memory saving kludge script; it is the combination of the canonical huffware
+// scripts: (1) non-script giver, (2) rotanium rotato, (3) text label.
+// our theory is that by having only two scripts per display object (this script and
+// the updater client) instead of four, we'll save some cpu on our overburdened but
+// beloved server (serene).
+// given that this script is intended to replace those three scripts, it will eat them
+// on startup to avoid having redundant services in the object.
+// update for april 24 2011: added a question menu before doing the copying to user's
+// inventory, since opensim can do a weird thing that sets all folders to "loading...".
+// this now keeps the objects from being super annoying when one didn't mean to click it.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// non-script giver:
+//
+// gives all objects, notecards, etc contained in an object when that object is touched.
+// does not give out scripts, since these are generally not something that should be handed
+// to the customer.
+//
+// rotanium rotato:
+//
+// causes the object to rotate according to the parameters set below.
+// this can use herky-jerky timed rotation with llSetRot or it can use
+// smooth rotation with llTargetOmega.
+//
+// text label:
+//
+// a super simple script for giving an object readable text.
+
+integer DEBUGGING = FALSE;  // set to true for noisier runs.
+
+integer DO_ROTATION = TRUE;  // is this the rotating version or not?
+
+integer USE_SENSORS = TRUE;  // should we look for avatars so we can display the label?
+
+float SMOOTH_TIMER_FREQUENCY = 7.0;
+    // fastest possible rate of change for the smooth rotater, in seconds.  the smooth
+    // rotater doesn't need to hit the timer all that often, but this is faster than it
+    // needs to be for rotation, since it is also used as the rate at which the avatar sensor
+    // fires.
+
+float TIME_TO_CLEAR_TITLE = 8.0;
+    // how many seconds before the title that was set for an avatar or due to a touch will
+    // disappear again.
+
+vector LABEL_COLOR = <0.3, 0.9, 0.4>;
+    // color of the text above object.
+
+float ACTIVE_LABEL_DISTANCE = 5.0;
+    // how far away can avatars cause the label to light up?
+
+integer ONLY_GIVE_TO_OWNER = TRUE;
+    // if this is true, then only the owner will receive a copy of the items.
+
+integer GIVE_UNCOPYABLES = FALSE;
+    // this flag is dangerous when true, because it means that uncopyable objects will still
+    // be handed to the target.  if that target refuses the non-copyable items, then the items
+    // will be lost forever.  that is not so good if you've sold the person a non-copy item.
+
+string EXCLUDED_NOTECARD = "product description";
+    // a special case; if there is a giftorse configuration card, we won't hand that out.
+
+float SMOOTH_CHANCE_FOR_ADJUSTING = 0.28;
+    // we won't always change the smooth rotation, even though our timer is pretty slow.
+    // this value is the percentage of the time that we do actually change rotation (divided
+    // by 100).
+
+float SMOOTH_ROTATION_GAIN_MAX = 0.0490873852122;
+    // the gain is how fast we will rotate in radians per second.
+    // PI / 2 is about 90 degrees per second, which seems way too fast.
+    // 0.196349540849 is about PI / 16, 0.0981747704244 is about PI / 32,
+    // and 0.0490873852122 is about PI / 64.
+
+string object_label = "default";  // change this if you want a specific name.
+
+string old_name;  // tracks the last known name so we know if we need to update title.
+float old_opacity = 3.14;  // tracks the last opacity setting for the label.
+
+integer label_changed = TRUE;
+    // this remembers if the label has stayed put or not.  we use it to decide
+    // whether we need to check the label for carriage returns.
+
+vector current_add_in = <0.0, 0.0, 0.4>;
+    // randomly assigned to if RANDOMIZE_ROTATION is true.
+
+float current_gain = -0.05;
+    // speed of smooth rotation; will randomly change if RANDOMIZE_ROTATION is true.
+
+float MIN_ADDITION = 0.01;
+    // smallest amount of change we will ever have.
+float MAX_ADDITION = 7.0;
+    // largest amount of change we will ever have.
+
+key first_toucher;  // tracks who clicked on the object to get contents.
+
+float label_opacity = 1.0;  // how opaque should text be?  1.0 is solid, 0.0 transparent.
+
+// takes out the 3 scripts that have been combined into the mux.  otherwise, it's
+// more of a pain to update all the boxes with this thing when it's ready to go.
+remove_redundant_scripts()
+{
+    integer posn;
+    string self = llGetScriptName();
+    // zoom across the scripts to see if we have any in the inventory that
+    // are slated for removal.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if (curr_script != self) {
+            if ( (llSubStringIndex(curr_script, "non-script giver") == 0)
+                || (llSubStringIndex(curr_script, "rotanium rotato") == 0)
+                || (llSubStringIndex(curr_script, "text label") == 0) ) {
+                // this one is a match!  zap it.
+                llRemoveInventory(curr_script);
+            }
+            
+        }
+    }
+}
+
+// the avatar has said it's okay to hand out all the stuff to her/him.
+really_give_contents() { give_out_contents(first_toucher); }
+
+// give out pictures, notecards, objects, etc. that are hiding in the object.
+give_out_contents(key give_to)
+{
+    list all_to_give = [];  // the set we will hand over in a batch.
+    list uncopyables = [];  // the list we have to do individually.
+    // find out how many items there are.
+    integer count = llGetInventoryNumber(INVENTORY_ALL);
+    // iterate across all the items and add them to the gift list if appropriate.
+    integer indy;
+    for (indy = 0; indy < count; indy++) {
+        string item_name = llGetInventoryName(INVENTORY_ALL, indy);
+        integer type = llGetInventoryType(item_name);
+        if ( (type != INVENTORY_SCRIPT) 
+            && ( (type != INVENTORY_NOTECARD) || (item_name != EXCLUDED_NOTECARD) ) ) {
+            // it's okay to add this item; it's not a script and we are not skipping the special notecard.
+            integer mask = MASK_OWNER;
+            if (!ONLY_GIVE_TO_OWNER) mask = MASK_EVERYONE;
+            integer perms = llGetInventoryPermMask(item_name, mask);
+            if (perms & PERM_COPY) {
+                // a normal object that we can hand out.
+                all_to_give += item_name;
+            } else {
+                uncopyables += item_name;
+            }
+        }
+    }
+    // hand the customer the whole set as one big chunk, named after the object.
+    llGiveInventoryList(give_to, llGetObjectName(), all_to_give);
+
+    // handle any problematic items.  we cannot copy these objects into a category folder,
+    // so we can either not try to copy them (a lot safer) or we can try to deliver them
+    // normally as individual items.  the latter choice is more dangerous, because if the
+    // owner discards these items rather than keeping them, the items will be lost forever!
+    if (llGetListLength(uncopyables) > 0) {
+        string plural = " ";
+        string is_verb = "is ";
+        string third_noun_subj = "it ";
+        string third_noun_obj = "it ";
+        if (llGetListLength(uncopyables) > 1) {
+            plural = "s ";
+            is_verb = "are ";
+            third_noun_subj = "they ";
+            third_noun_obj = "them ";
+        }
+        
+        string uncopyable_message = "will be left inside the object.  To get " + third_noun_obj
+            + ", please copy " + third_noun_obj + "\nmanually from this object into your inventory.";
+        if (GIVE_UNCOPYABLES) {
+            uncopyable_message = "will be moved over to your inventory."
+            + "\nPlease look in your main folders for "
+            + third_noun_obj + "(e.g., in Objects or Textures).";
+        }
+        
+        string failure_message = "The item" + plural
+            + "[" + llDumpList2String(uncopyables, "; ") + "]\n"
+            + is_verb + "not copyable; " + third_noun_subj
+            + uncopyable_message;
+            
+        if (llGetOwner() == give_to) {
+            // the object can be moved to inventory, but not with the category method.
+            llOwnerSay(failure_message);
+        } else {
+            // this seems like a weird case; it will probably just fail anyhow?
+            // if the item's not copyable and you're not the owner of this object,
+            // how can we give it to you?
+            llInstantMessage(give_to, failure_message);
+        }
+        
+        // now that we've announced this weird situation, handle it appropriately.
+        if (GIVE_UNCOPYABLES) {
+            for (indy = 0; indy < llGetListLength(uncopyables); indy++) {
+                string item_name = llList2String(uncopyables, indy);
+                llGiveInventory(give_to, item_name);
+            }
+        }  // otherwise leave them be.
+    }
+}
+
+// causes the object to rotate using whatever the current settings are.
+smooth_rotate_using_our_settings()
+{
+    // make sure we are using the rotational values we were asked to.
+    llTargetOmega(current_add_in, current_gain, 1.0);
+}
+
+// sets the gain and add in to random choices.
+randomize_values()
+{
+    current_gain = randomize_within_range(0.001, SMOOTH_ROTATION_GAIN_MAX, TRUE);
+    current_add_in = random_vector(MIN_ADDITION, MAX_ADDITION, TRUE);
+}
+
+// performs the timed rotation that has been configured for us.
+rotate_as_requested()
+{
+    // our slack timer went off, so randomize the rotation if requested.
+    if (llFrand(1.0) >= (1.0 - SMOOTH_CHANCE_FOR_ADJUSTING) ) {
+        randomize_values();
+        smooth_rotate_using_our_settings();
+    }
+}
+
+initialize_fredboxmux()
+{
+    // make sure we pick a good random channel.
+    menu_system_channel = -1 * (integer)randomize_within_range(200, 10000000, FALSE);
+
+    // if needed, we will set our initial random rotation.
+    randomize_values();
+        
+    // do a first rotate, so we move right at startup.  otherwise we won't move
+    // until after our first timer hits.
+    if (DO_ROTATION) rotate_as_requested();
+
+    // now set the timer for our mode.
+    llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
+    if (DO_ROTATION) smooth_rotate_using_our_settings();
+}
+
+set_text()
+{
+//log_it("old name " + old_name + " -- curr name " + llGetObjectName());
+    if (old_name != llGetObjectName()) {
+        // we're out of synch on the object name.
+        label_changed = TRUE;
+    }
+    if (old_opacity != label_opacity) {
+        // here we're out of synch on last opacity used.
+        label_changed = TRUE;
+    }
+    if (label_changed) {
+        // reset the object title to a decorated version of object name if it says "default".
+        string new_label = object_label;
+        if (new_label == "default") new_label = llGetObjectName();
+    
+        integer indy;
+        integer keep_going = TRUE;
+        while (keep_going) {
+            indy = find_substring(new_label, "\\n");
+            if (indy < 0) {
+                keep_going = FALSE;
+            } else {
+                new_label = llGetSubString(new_label, 0, indy - 1)
+                    + "\n" + llGetSubString(new_label, indy + 2, -1);
+            }
+        }
+        old_name = llGetObjectName();
+        old_opacity = label_opacity;
+        label_changed = FALSE;  // we have dealt with it now.
+//log_it("setting text: " + new_label);
+        llSetText(new_label, LABEL_COLOR, label_opacity);
+    }
+    if (label_opacity != 0) {
+        // if we set a lit-up title, clear it again pretty soon.
+        llSetTimerEvent(TIME_TO_CLEAR_TITLE);
+    }
+}
+
+//////////////
+// code borrowed from menutini to raise a menu asking if they actually meant to get all
+// the contents.  an opensim inventory bug makes all the folders look foolish if we
+// do any inventory giving accidentally.
+//////////////
+
+// global variables...
+
+list _private_global_buttons;  // holds onto the active set of menu options.
+string _private_global_av_key;  // the key for the avatar who clicks the menu.
+string _private_global_title;  // holds onto current title text.
+
+integer _menu_base_start = 0;  // position in the items of the current menu.
+
+integer listening_id = 0;
+    // the current id of our listening for the menu.  it's an id returned by LSL
+    // that we need to track so we can cancel the listen.
+
+integer menu_system_channel = -123;
+    // messages come back to us from this channel when user clicks the dialog.
+    // this is set later and the default is meaningless.
+
+string global_menu_name = "";
+    // hangs onto the current menu's name.
+
+//hmmm: note; to manage multiple concurrent menus on different channels,
+//      we must make these into lists.  then the timeouts should apply
+//      individually to these instead of overall (if we even do timeouts;
+//      it's nicer if menus never stop being active).
+
+string NEXT_MENU_TEXT = "Next >>";
+    // what the next item will say for showing next menu page.
+    
+//integer TIMEOUT_FOR_MENU = 42;
+    // timeout for the menu in seconds.
+
+// displays the menu requested.  it's "menu_name" is an internal name that is
+// not displayed to the user.  the "title" is the content shown in the main area
+// of the menu.  "commands_in" is the list of menu items to show as buttons.
+// the "menu_channel" is where the user's clicked response will be sent.  the
+// "listen_to" key is the avatar expected to click the menu, which is needed to
+// listen to his response.
+show_menu(string menu_name, string title, list buttons,
+    integer menu_channel, key listen_to)
+{
+    // save our new parms.
+    global_menu_name = menu_name;
+    _private_global_title = title;
+    _private_global_buttons = buttons;
+    menu_system_channel = menu_channel;
+    _private_global_av_key = listen_to;
+    if (DEBUGGING) {
+        log_it("menu name: " + global_menu_name);
+        log_it("title: " + _private_global_title);
+        log_it("buttons: " + (string)buttons);
+        log_it("channel: " + (string)menu_system_channel);
+        log_it("listen key: " + (string)listen_to);
+    }
+
+    integer add_next = FALSE;  // true if we should add a next menu item.
+
+    // the math here incorporates current button position.
+    integer current = _menu_base_start;
+    integer max_buttons = llGetListLength(buttons) - current;
+
+    if (max_buttons > 12) {
+        // limitation of SL: menus have a max of 12 buttons.
+        max_buttons = 12;
+        add_next = TRUE;
+    } else if (llGetListLength(buttons) > 12) {
+        // we already have been adding next.  let's make sure this gets
+        // a wrap-around next button.
+        add_next = TRUE;
+    }
+    // chop out what we can use in a menu.
+    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
+    if (add_next) {
+        // we were asked to add a menu item for the next screen.
+        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
+    }
+
+    listening_id = llListen(menu_channel, "", listen_to, "");
+    list commands;
+    integer i;
+    // take only the prefix of the string, to avoid getting a length complaint.
+    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
+        string curr = llList2String(trunc_buttons, i);
+        integer last_pos = 23;  // default maximum, highest possible is 24.
+        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
+        curr = llGetSubString(curr, 0, last_pos);
+        commands += curr;
+    }
+    llDialog(listen_to, title, commands, menu_channel);
+}
+
+// shuts down any connection we might have had with any active menu.  we will not
+// send any responses after this point (although we might already have responded when
+// the user clicked the menu).
+clear_menu()
+{
+    llListenRemove(listening_id);
+}
+
+// process the response when the user chooses a menu item.
+process_menu_response(integer channel, string name, key id, string message)
+{
+  if (channel != menu_system_channel) return;  // not for us.
+  
+    if (message == NEXT_MENU_TEXT) {
+        // this is the special choice, so we need to go to the next page.
+        _menu_base_start += 11;
+        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
+            // we have wrapped around the list.  go to the start again.
+            _menu_base_start = 0;
+        }
+        show_menu(global_menu_name, _private_global_title,
+            _private_global_buttons, menu_system_channel,
+            _private_global_av_key);
+        return;  // handled by opening a new menu.
+    }
+    
+    string calculated_name;
+    integer indy;
+    // first try for an exact match.
+    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+        string curr = llList2String(_private_global_buttons, indy);
+        if (curr == message) {
+            // correct the answer based on the full button string.
+            calculated_name = curr;
+        }
+    }
+    if (calculated_name == "") {
+        // try an imprecise match if the exact matching didn't work.
+        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+            string curr = llList2String(_private_global_buttons, indy);
+            if (is_prefix(curr, message)) {
+                // correct the answer based on the full button string.
+                calculated_name = curr;
+            }
+        }
+    }
+    if (calculated_name == "yes") {
+        // only send a response if that menu choice made sense to us.
+        really_give_contents();
+        clear_menu();
+    }
+}
+
+// end from menutini.
+//////////////
+
+//////////////
+// start of hufflets...
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+//////////////
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//end hufflets...
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        remove_redundant_scripts();
+        initialize_fredboxmux();
+        label_opacity = 1;  // start out showing the label.
+        set_text();
+    }
+    
+    on_rez(integer start_parm) { state default; }
+    
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            // we show the label at least a bit when the contents change.
+            label_opacity = 1;
+            set_text(); 
+        }
+    }
+    
+    touch_start(integer num) {
+        label_opacity = 1.0;
+        set_text();
+        first_toucher = llDetectedKey(0);
+        // are we only supposed to give stuff to the owner?
+        if (ONLY_GIVE_TO_OWNER && (first_toucher != llGetOwner()) ) {
+            first_toucher = NULL_KEY;
+            return;  // bail out.
+        }
+        show_menu("askreally", "Would you like a copy of this object's contents?",
+            ["yes", "no"], -18264, first_toucher);
+    }
+
+    listen(integer channel, string name, key id, string message)
+    { process_menu_response(channel, name, id, message); }
+
+    timer() {
+        llSetTimerEvent(0);
+        if (DO_ROTATION) rotate_as_requested();
+        if (USE_SENSORS) {
+            llSensor("", NULL_KEY, AGENT, ACTIVE_LABEL_DISTANCE, PI);
+        } else {
+            if (label_opacity != 0.0) {
+                label_opacity = 0.0;
+                set_text();
+            }            
+        }
+        llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
+    }
+
+    sensor(integer count) {
+        if (label_opacity != 1.0) {
+            label_opacity = 1.0;
+            set_text();
+        }
+    }
+    
+    no_sensor() {
+        if (label_opacity != 0.0) {
+            label_opacity = 0.0;
+            set_text();
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_v3.0.txt b/huffware/huffotronic_updater_freebie_v5.3/fredboxmux_v3.0.txt
deleted file mode 100755 (executable)
index c41662c..0000000
+++ /dev/null
@@ -1,669 +0,0 @@
-
-// huffware script: fredboxmux (with rotation), by fred huffhines.
-//
-// a memory saving kludge script; it is the combination of the canonical huffware
-// scripts: (1) non-script giver, (2) rotanium rotato, (3) text label.
-// our theory is that by having only two scripts per display object (this script and
-// the updater client) instead of four, we'll save some cpu on our overburdened but
-// beloved server (serene).
-// given that this script is intended to replace those three scripts, it will eat them
-// on startup to avoid having redundant services in the object.
-// update for april 24 2011: added a question menu before doing the copying to user's
-// inventory, since opensim can do a weird thing that sets all folders to "loading...".
-// this now keeps the objects from being super annoying when one didn't mean to click it.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// non-script giver:
-//
-// gives all objects, notecards, etc contained in an object when that object is touched.
-// does not give out scripts, since these are generally not something that should be handed
-// to the customer.
-//
-// rotanium rotato:
-//
-// causes the object to rotate according to the parameters set below.
-// this can use herky-jerky timed rotation with llSetRot or it can use
-// smooth rotation with llTargetOmega.
-//
-// text label:
-//
-// a super simple script for giving an object readable text.
-
-integer DEBUGGING = FALSE;  // set to true for noisier runs.
-
-integer DO_ROTATION = TRUE;  // is this the rotating version or not?
-
-integer USE_SENSORS = TRUE;  // should we look for avatars so we can display the label?
-
-float SMOOTH_TIMER_FREQUENCY = 7.0;
-    // fastest possible rate of change for the smooth rotater, in seconds.  the smooth
-    // rotater doesn't need to hit the timer all that often, but this is faster than it
-    // needs to be for rotation, since it is also used as the rate at which the avatar sensor
-    // fires.
-
-float TIME_TO_CLEAR_TITLE = 8.0;
-    // how many seconds before the title that was set for an avatar or due to a touch will
-    // disappear again.
-
-vector LABEL_COLOR = <0.3, 0.9, 0.4>;
-    // color of the text above object.
-
-float ACTIVE_LABEL_DISTANCE = 5.0;
-    // how far away can avatars cause the label to light up?
-
-integer ONLY_GIVE_TO_OWNER = TRUE;
-    // if this is true, then only the owner will receive a copy of the items.
-
-integer GIVE_UNCOPYABLES = FALSE;
-    // this flag is dangerous when true, because it means that uncopyable objects will still
-    // be handed to the target.  if that target refuses the non-copyable items, then the items
-    // will be lost forever.  that is not so good if you've sold the person a non-copy item.
-
-string EXCLUDED_NOTECARD = "product description";
-    // a special case; if there is a giftorse configuration card, we won't hand that out.
-
-float SMOOTH_CHANCE_FOR_ADJUSTING = 0.28;
-    // we won't always change the smooth rotation, even though our timer is pretty slow.
-    // this value is the percentage of the time that we do actually change rotation (divided
-    // by 100).
-
-float SMOOTH_ROTATION_GAIN_MAX = 0.0490873852122;
-    // the gain is how fast we will rotate in radians per second.
-    // PI / 2 is about 90 degrees per second, which seems way too fast.
-    // 0.196349540849 is about PI / 16, 0.0981747704244 is about PI / 32,
-    // and 0.0490873852122 is about PI / 64.
-
-string object_label = "default";  // change this if you want a specific name.
-
-string old_name;  // tracks the last known name so we know if we need to update title.
-float old_opacity = 3.14;  // tracks the last opacity setting for the label.
-
-integer label_changed = TRUE;
-    // this remembers if the label has stayed put or not.  we use it to decide
-    // whether we need to check the label for carriage returns.
-
-vector current_add_in = <0.0, 0.0, 0.4>;
-    // randomly assigned to if RANDOMIZE_ROTATION is true.
-
-float current_gain = -0.05;
-    // speed of smooth rotation; will randomly change if RANDOMIZE_ROTATION is true.
-
-float MIN_ADDITION = 0.01;
-    // smallest amount of change we will ever have.
-float MAX_ADDITION = 7.0;
-    // largest amount of change we will ever have.
-
-key first_toucher;  // tracks who clicked on the object to get contents.
-
-float label_opacity = 1.0;  // how opaque should text be?  1.0 is solid, 0.0 transparent.
-
-// takes out the 3 scripts that have been combined into the mux.  otherwise, it's
-// more of a pain to update all the boxes with this thing when it's ready to go.
-remove_redundant_scripts()
-{
-    integer posn;
-    string self = llGetScriptName();
-    // zoom across the scripts to see if we have any in the inventory that
-    // are slated for removal.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if (curr_script != self) {
-            if ( (llSubStringIndex(curr_script, "non-script giver") == 0)
-                || (llSubStringIndex(curr_script, "rotanium rotato") == 0)
-                || (llSubStringIndex(curr_script, "text label") == 0) ) {
-                // this one is a match!  zap it.
-                llRemoveInventory(curr_script);
-            }
-            
-        }
-    }
-}
-
-// the avatar has said it's okay to hand out all the stuff to her/him.
-really_give_contents() { give_out_contents(first_toucher); }
-
-// give out pictures, notecards, objects, etc. that are hiding in the object.
-give_out_contents(key give_to)
-{
-    list all_to_give = [];  // the set we will hand over in a batch.
-    list uncopyables = [];  // the list we have to do individually.
-    // find out how many items there are.
-    integer count = llGetInventoryNumber(INVENTORY_ALL);
-    // iterate across all the items and add them to the gift list if appropriate.
-    integer indy;
-    for (indy = 0; indy < count; indy++) {
-        string item_name = llGetInventoryName(INVENTORY_ALL, indy);
-        integer type = llGetInventoryType(item_name);
-        if ( (type != INVENTORY_SCRIPT) 
-            && ( (type != INVENTORY_NOTECARD) || (item_name != EXCLUDED_NOTECARD) ) ) {
-            // it's okay to add this item; it's not a script and we are not skipping the special notecard.
-            integer mask = MASK_OWNER;
-            if (!ONLY_GIVE_TO_OWNER) mask = MASK_EVERYONE;
-            integer perms = llGetInventoryPermMask(item_name, mask);
-            if (perms & PERM_COPY) {
-                // a normal object that we can hand out.
-                all_to_give += item_name;
-            } else {
-                uncopyables += item_name;
-            }
-        }
-    }
-    // hand the customer the whole set as one big chunk, named after the object.
-    llGiveInventoryList(give_to, llGetObjectName(), all_to_give);
-
-    // handle any problematic items.  we cannot copy these objects into a category folder,
-    // so we can either not try to copy them (a lot safer) or we can try to deliver them
-    // normally as individual items.  the latter choice is more dangerous, because if the
-    // owner discards these items rather than keeping them, the items will be lost forever!
-    if (llGetListLength(uncopyables) > 0) {
-        string plural = " ";
-        string is_verb = "is ";
-        string third_noun_subj = "it ";
-        string third_noun_obj = "it ";
-        if (llGetListLength(uncopyables) > 1) {
-            plural = "s ";
-            is_verb = "are ";
-            third_noun_subj = "they ";
-            third_noun_obj = "them ";
-        }
-        
-        string uncopyable_message = "will be left inside the object.  To get " + third_noun_obj
-            + ", please copy " + third_noun_obj + "\nmanually from this object into your inventory.";
-        if (GIVE_UNCOPYABLES) {
-            uncopyable_message = "will be moved over to your inventory."
-            + "\nPlease look in your main folders for "
-            + third_noun_obj + "(e.g., in Objects or Textures).";
-        }
-        
-        string failure_message = "The item" + plural
-            + "[" + llDumpList2String(uncopyables, "; ") + "]\n"
-            + is_verb + "not copyable; " + third_noun_subj
-            + uncopyable_message;
-            
-        if (llGetOwner() == give_to) {
-            // the object can be moved to inventory, but not with the category method.
-            llOwnerSay(failure_message);
-        } else {
-            // this seems like a weird case; it will probably just fail anyhow?
-            // if the item's not copyable and you're not the owner of this object,
-            // how can we give it to you?
-            llInstantMessage(give_to, failure_message);
-        }
-        
-        // now that we've announced this weird situation, handle it appropriately.
-        if (GIVE_UNCOPYABLES) {
-            for (indy = 0; indy < llGetListLength(uncopyables); indy++) {
-                string item_name = llList2String(uncopyables, indy);
-                llGiveInventory(give_to, item_name);
-            }
-        }  // otherwise leave them be.
-    }
-}
-
-// causes the object to rotate using whatever the current settings are.
-smooth_rotate_using_our_settings()
-{
-    // make sure we are using the rotational values we were asked to.
-    llTargetOmega(current_add_in, current_gain, 1.0);
-}
-
-// sets the gain and add in to random choices.
-randomize_values()
-{
-    current_gain = randomize_within_range(0.001, SMOOTH_ROTATION_GAIN_MAX, TRUE);
-    current_add_in = random_vector(MIN_ADDITION, MAX_ADDITION, TRUE);
-}
-
-// performs the timed rotation that has been configured for us.
-rotate_as_requested()
-{
-    // our slack timer went off, so randomize the rotation if requested.
-    if (llFrand(1.0) >= (1.0 - SMOOTH_CHANCE_FOR_ADJUSTING) ) {
-        randomize_values();
-        smooth_rotate_using_our_settings();
-    }
-}
-
-initialize_fredboxmux()
-{
-    // make sure we pick a good random channel.
-    menu_system_channel = -1 * (integer)randomize_within_range(200, 10000000, FALSE);
-
-    // if needed, we will set our initial random rotation.
-    randomize_values();
-        
-    // do a first rotate, so we move right at startup.  otherwise we won't move
-    // until after our first timer hits.
-    if (DO_ROTATION) rotate_as_requested();
-
-    // now set the timer for our mode.
-    llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
-    if (DO_ROTATION) smooth_rotate_using_our_settings();
-}
-
-set_text()
-{
-//log_it("old name " + old_name + " -- curr name " + llGetObjectName());
-    if (old_name != llGetObjectName()) {
-        // we're out of synch on the object name.
-        label_changed = TRUE;
-    }
-    if (old_opacity != label_opacity) {
-        // here we're out of synch on last opacity used.
-        label_changed = TRUE;
-    }
-    if (label_changed) {
-        // reset the object title to a decorated version of object name if it says "default".
-        string new_label = object_label;
-        if (new_label == "default") new_label = llGetObjectName();
-    
-        integer indy;
-        integer keep_going = TRUE;
-        while (keep_going) {
-            indy = find_substring(new_label, "\\n");
-            if (indy < 0) {
-                keep_going = FALSE;
-            } else {
-                new_label = llGetSubString(new_label, 0, indy - 1)
-                    + "\n" + llGetSubString(new_label, indy + 2, -1);
-            }
-        }
-        old_name = llGetObjectName();
-        old_opacity = label_opacity;
-        label_changed = FALSE;  // we have dealt with it now.
-//log_it("setting text: " + new_label);
-        llSetText(new_label, LABEL_COLOR, label_opacity);
-    }
-    if (label_opacity != 0) {
-        // if we set a lit-up title, clear it again pretty soon.
-        llSetTimerEvent(TIME_TO_CLEAR_TITLE);
-    }
-}
-
-//////////////
-// code borrowed from menutini to raise a menu asking if they actually meant to get all
-// the contents.  an opensim inventory bug makes all the folders look foolish if we
-// do any inventory giving accidentally.
-//////////////
-
-// global variables...
-
-list _private_global_buttons;  // holds onto the active set of menu options.
-string _private_global_av_key;  // the key for the avatar who clicks the menu.
-string _private_global_title;  // holds onto current title text.
-
-integer _menu_base_start = 0;  // position in the items of the current menu.
-
-integer listening_id = 0;
-    // the current id of our listening for the menu.  it's an id returned by LSL
-    // that we need to track so we can cancel the listen.
-
-integer menu_system_channel = -123;
-    // messages come back to us from this channel when user clicks the dialog.
-    // this is set later and the default is meaningless.
-
-string global_menu_name = "";
-    // hangs onto the current menu's name.
-
-//hmmm: note; to manage multiple concurrent menus on different channels,
-//      we must make these into lists.  then the timeouts should apply
-//      individually to these instead of overall (if we even do timeouts;
-//      it's nicer if menus never stop being active).
-
-string NEXT_MENU_TEXT = "Next >>";
-    // what the next item will say for showing next menu page.
-    
-//integer TIMEOUT_FOR_MENU = 42;
-    // timeout for the menu in seconds.
-
-// displays the menu requested.  it's "menu_name" is an internal name that is
-// not displayed to the user.  the "title" is the content shown in the main area
-// of the menu.  "commands_in" is the list of menu items to show as buttons.
-// the "menu_channel" is where the user's clicked response will be sent.  the
-// "listen_to" key is the avatar expected to click the menu, which is needed to
-// listen to his response.
-show_menu(string menu_name, string title, list buttons,
-    integer menu_channel, key listen_to)
-{
-    // save our new parms.
-    global_menu_name = menu_name;
-    _private_global_title = title;
-    _private_global_buttons = buttons;
-    menu_system_channel = menu_channel;
-    _private_global_av_key = listen_to;
-    if (DEBUGGING) {
-        log_it("menu name: " + global_menu_name);
-        log_it("title: " + _private_global_title);
-        log_it("buttons: " + (string)buttons);
-        log_it("channel: " + (string)menu_system_channel);
-        log_it("listen key: " + (string)listen_to);
-    }
-
-    integer add_next = FALSE;  // true if we should add a next menu item.
-
-    // the math here incorporates current button position.
-    integer current = _menu_base_start;
-    integer max_buttons = llGetListLength(buttons) - current;
-
-    if (max_buttons > 12) {
-        // limitation of SL: menus have a max of 12 buttons.
-        max_buttons = 12;
-        add_next = TRUE;
-    } else if (llGetListLength(buttons) > 12) {
-        // we already have been adding next.  let's make sure this gets
-        // a wrap-around next button.
-        add_next = TRUE;
-    }
-    // chop out what we can use in a menu.
-    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
-    if (add_next) {
-        // we were asked to add a menu item for the next screen.
-        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
-    }
-
-    listening_id = llListen(menu_channel, "", listen_to, "");
-    list commands;
-    integer i;
-    // take only the prefix of the string, to avoid getting a length complaint.
-    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
-        string curr = llList2String(trunc_buttons, i);
-        integer last_pos = 23;  // default maximum, highest possible is 24.
-        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
-        curr = llGetSubString(curr, 0, last_pos);
-        commands += curr;
-    }
-    llDialog(listen_to, title, commands, menu_channel);
-}
-
-// shuts down any connection we might have had with any active menu.  we will not
-// send any responses after this point (although we might already have responded when
-// the user clicked the menu).
-clear_menu()
-{
-    llListenRemove(listening_id);
-}
-
-// process the response when the user chooses a menu item.
-process_menu_response(integer channel, string name, key id, string message)
-{
-  if (channel != menu_system_channel) return;  // not for us.
-  
-    if (message == NEXT_MENU_TEXT) {
-        // this is the special choice, so we need to go to the next page.
-        _menu_base_start += 11;
-        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
-            // we have wrapped around the list.  go to the start again.
-            _menu_base_start = 0;
-        }
-        show_menu(global_menu_name, _private_global_title,
-            _private_global_buttons, menu_system_channel,
-            _private_global_av_key);
-        return;  // handled by opening a new menu.
-    }
-    
-    string calculated_name;
-    integer indy;
-    // first try for an exact match.
-    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-        string curr = llList2String(_private_global_buttons, indy);
-        if (curr == message) {
-            // correct the answer based on the full button string.
-            calculated_name = curr;
-        }
-    }
-    if (calculated_name == "") {
-        // try an imprecise match if the exact matching didn't work.
-        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-            string curr = llList2String(_private_global_buttons, indy);
-            if (is_prefix(curr, message)) {
-                // correct the answer based on the full button string.
-                calculated_name = curr;
-            }
-        }
-    }
-    if (calculated_name == "yes") {
-        // only send a response if that menu choice made sense to us.
-        really_give_contents();
-        clear_menu();
-    }
-}
-
-// end from menutini.
-//////////////
-
-//////////////
-// start of hufflets...
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-//////////////
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//end hufflets...
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        remove_redundant_scripts();
-        initialize_fredboxmux();
-        label_opacity = 1;  // start out showing the label.
-        set_text();
-    }
-    
-    on_rez(integer start_parm) { state default; }
-    
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            // we show the label at least a bit when the contents change.
-            label_opacity = 1;
-            set_text(); 
-        }
-    }
-    
-    touch_start(integer num) {
-        label_opacity = 1.0;
-        set_text();
-        first_toucher = llDetectedKey(0);
-        // are we only supposed to give stuff to the owner?
-        if (ONLY_GIVE_TO_OWNER && (first_toucher != llGetOwner()) ) {
-            first_toucher = NULL_KEY;
-            return;  // bail out.
-        }
-        show_menu("askreally", "Would you like a copy of this object's contents?",
-            ["yes", "no"], -18264, first_toucher);
-    }
-
-    listen(integer channel, string name, key id, string message)
-    { process_menu_response(channel, name, id, message); }
-
-    timer() {
-        llSetTimerEvent(0);
-        if (DO_ROTATION) rotate_as_requested();
-        if (USE_SENSORS) {
-            llSensor("", NULL_KEY, AGENT, ACTIVE_LABEL_DISTANCE, PI);
-        } else {
-            if (label_opacity != 0.0) {
-                label_opacity = 0.0;
-                set_text();
-            }            
-        }
-        llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
-    }
-
-    sensor(integer count) {
-        if (label_opacity != 1.0) {
-            label_opacity = 1.0;
-            set_text();
-        }
-    }
-    
-    no_sensor() {
-        if (label_opacity != 0.0) {
-            label_opacity = 0.0;
-            set_text();
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/huff-update_client_v20.1.lsl b/huffware/huffotronic_updater_freebie_v5.3/huff-update_client_v20.1.lsl
new file mode 100755 (executable)
index 0000000..4a458bb
--- /dev/null
@@ -0,0 +1,826 @@
+
+// huffware script: huff-update client, by fred huffhines.
+//
+// this script is the client side of the update process.  it should reside in an object that
+// has scripts which should be automatically updated.  it will listen for announcements by
+// an update server and communicate with the server to ensure that all of its scripts are
+// the most up to date available with the server.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// global constants...
+
+integer DEBUGGING = FALSE;  // if TRUE, the script will output status information.
+
+integer SERVER_IGNORE_TIME = 1200;  // number of seconds between performing an upgrade with the same server.
+
+integer MAXIMUM_UPDATE_TIME_ALLOWED = 140;  // we allow one upgrade process to take this long overall.
+
+integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
+integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
+
+string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
+string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
+string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
+string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
+string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
+string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
+string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
+string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
+string DONE_UPDATING                = "#finito#";  // the client is done updating.
+string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
+
+float UPDATE_TIMER_INTERVAL = 2.0;  // interval between checks on our update status.
+
+integer UPDATER_SCRIPT_PIN = -1231008;  // the hook for our scripts to be modified.
+
+///float BUSY_SERVER_PAUSE_TIME = 38.0;  // num seconds to delay when server says it's too busy.
+
+string UPDATER_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+
+string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
+string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
+
+integer MAXIMUM_SERVERS_TRACKED = 32;
+    // we will listen to this many servers before we decide to remove one.
+
+string CONTINUANCE_MARKER = "...";
+    // a string sent when the update list is too long and needs to be continued in another chat.
+
+string SERVER_SCRIPT = "a huffotronic update server";
+    // the prefix of our server script that hands out updates.
+
+// global variables...
+
+integer inventory_request_channel;  // used for newer version servers to cut down cross chatter.
+list updaters_heard;  // the update servers we've heard from recently.
+list last_interactions;  // times of the last update process engaged with the updater.
+integer update_channel;  // current channel for interaction with specific server.
+key current_server;  // the updater that is active right now, if any.
+integer update_start_time;  // when the last update process began.
+list updates_needed;  // stores the set of scripts that are in need of an update.
+list known_script_dependencies;  // stores the list of dependency info.
+
+careful_crankup()
+{
+    knock_around_other_scripts(TRUE);
+    // clean out the older items and scripts.  we do this after getting everyone running
+    // since we might be whacking ourselves.
+    destroy_older_versions();
+}
+
+// reset our variables.
+initialize()
+{
+    updaters_heard = [];
+    last_interactions = [];
+    inventory_request_channel = 0;
+    update_channel = 0;
+    current_server = NULL_KEY;
+    llSetTimerEvent(0.0);
+    llSetRemoteScriptAccessPin(UPDATER_SCRIPT_PIN);
+    // a new enhancements; tells the server that this guy has finished an update cycle.  this
+    // only comes into play when the updater script itself has just been updated, but it's
+    // nice for the server to avoid claiming erroneous timeouts occurred.
+    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
+    llSleep(0.4);  // snooze and repeat to overcome occasionally lossy chats.
+    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
+}
+
+whack_updater_record(key id)
+{
+    integer prev_indy = find_in_list(updaters_heard, id);
+    if (prev_indy < 0) return;  // not there.
+    updaters_heard = chop_list(updaters_heard, 0, prev_indy - 1)
+            + chop_list(updaters_heard, prev_indy + 1, llGetListLength(updaters_heard) - 1);
+    last_interactions = chop_list(last_interactions, 0, prev_indy - 1)
+            + chop_list(last_interactions, prev_indy + 1, llGetListLength(last_interactions) - 1);
+}
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        if (DEBUGGING)
+            log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+    // thirdly, try to clean out the notecards.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
+}
+
+// sets the object to be listening for update info.
+// if "just_owner" is true, then we will not listen on the general announcement channel.
+listen_for_orders(integer just_owner)
+{
+    if (!just_owner) {
+        // try to hear an update being announced.
+        llListen(UPDATE_ANNOUNCEMENT_CHANNEL, "", NULL_KEY, "");
+    }
+
+    // super secret owner controls.
+    llListen(0, "", llGetOwner(), "");
+}
+
+// returns true if this object is a huffotronic updater of some sort.
+integer inside_of_updater()
+{
+    return find_substring(llGetObjectName(), "huffotronic") >= 0;
+}
+
+// returns true if a script is a version of our update server.
+integer matches_server_script(string to_check)
+{
+    return is_prefix(to_check, SERVER_SCRIPT);
+}
+
+// stops all the scripts besides this one.
+knock_around_other_scripts(integer running_state)
+{
+    integer insider = inside_of_updater();
+    if (running_state == TRUE) {
+        // make sure we crank up the scripts that are new first.  we want to reset them
+        // as well, which we don't want to do for any existing scripts.
+        integer crank_indy;
+        for (crank_indy = 0; crank_indy < llGetListLength(updates_needed); crank_indy++) {
+            string crankee = llList2String(updates_needed, crank_indy);
+            if (find_in_inventory(crankee, INVENTORY_SCRIPT, TRUE) >= 0) {
+                if (!insider || matches_server_script(crankee)) {
+                    // allow it to run again.
+                    llSetScriptState(crankee, TRUE);
+                    // reset it, to make sure it starts at the top.
+                    llResetOtherScript(crankee);
+                }
+            }
+        }
+    }
+
+    integer indy;
+    string self_script = llGetScriptName();
+    // we set all other scripts to the running state requested.
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if ( (curr_script != self_script)
+            && (!insider || matches_server_script(curr_script)) ) {
+            // this one seems ripe for being set to the state requested.
+            llSetScriptState(curr_script, running_state);
+        }
+    }
+}
+
+// a random channel for the interaction with the server.
+integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
+
+// make sure that any dependencies for the script with "basename" are added to the list
+// of requests we make during an update.
+list add_dependencies(string basename)
+{
+    list to_return;
+    integer indy;
+    for (indy = 0; indy < llGetListLength(known_script_dependencies); indy++) {
+        list deps = llParseString2List(llList2String(known_script_dependencies, indy),
+            [ITEM_LIST_SEPARATOR], []);
+//log_it("base=" + llList2String(dep, 0) + " lastver=" + llList2String(dep, 1) + " newdep=" + llList2String(dep, 2));
+        if (basename == llList2String(deps, 0)) {
+            // first off, is this item with new dependencies actually present?
+            integer where = find_in_inventory(basename, INVENTORY_SCRIPT, FALSE);
+            if (where >= 0) {
+                // we do use the script with deps, but is the dependent item really missing?
+                where = find_in_inventory(llList2String(deps, 1), INVENTORY_SCRIPT, FALSE);
+                if (where < 0) {
+                    // we found a dependency match for this script, so we'll ask for the missing item.
+                    if (DEBUGGING)
+                        log_it("missing dep: " + llList2String(deps, 1));
+                    to_return += [ llList2String(deps, 1) ];
+                }
+            }
+        }
+    }
+    return to_return;
+}
+
+// complains if memory seems to be getting tight.
+test_memory()
+{
+    if (llGetFreeMemory() < 4096)
+        log_it("mem_free = " + (string)llGetFreeMemory());
+}
+
+// starts an update given a list of scripts that the server has available, encoded as
+// a string in the "encoded_list".
+integer initiate_update(string encoded_list)
+{
+    list scripts_avail = llParseString2List(encoded_list, [UPDATER_PARM_SEPARATOR], []);
+    integer continue_listening_for_scripts = FALSE;
+      // if true, we aren't done hearing about available scripts yet.
+    encoded_list = "";
+    // figure out which scripts we need by comparing the list available from the server
+    // against our current inventory.  we only want scripts with newer version numbers.
+    integer sindy;
+    for (sindy = 0; sindy < llGetListLength(scripts_avail); sindy++) {
+        string curr = llList2String(scripts_avail, sindy);
+        if (curr == CONTINUANCE_MARKER) {
+            // this is a special continuation signal.  we need to hear the rest of the list.
+            continue_listening_for_scripts = TRUE;
+        } else if (is_prefix(curr, SCRIPT_DEPENDENCY_MARK)) {
+            // we've found a dependency item.
+            known_script_dependencies += [ llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1) ];
+//log_it("script dep: " + llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1));
+        } else {
+            list split = compute_basename_and_version(curr);
+            if (llGetListLength(split) == 2) {
+                string basename = llList2String(split, 0);
+                string version = llList2String(split, 1);
+                split = [];
+                integer oy_indy;
+//replace common code with func.
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_OBJECT); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_OBJECT, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+//                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+//                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_NOTECARD); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_NOTECARD, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_SCRIPT); oy_indy++) {
+                    list srv_split = compute_basename_and_version
+                        (llGetInventoryName(INVENTORY_SCRIPT, oy_indy));
+                    if ( (llGetListLength(srv_split) == 2)
+                            && (basename == llList2String(srv_split, 0))
+                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
+                        if (DEBUGGING) {
+                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
+                        }
+                        test_memory();
+                        updates_needed += [ curr ];
+                    }
+                }
+                updates_needed += add_dependencies(basename);
+            }
+        }
+    }
+    // we skip the next step if we're still waiting to hear about more.
+    if (continue_listening_for_scripts) {
+//log_it("still listening for more updates...");
+        return FALSE;
+    }
+    if (llGetListLength(updates_needed)) {
+//log_it("update chan=" + (string)update_channel);
+        llSay(update_channel, REQUEST_SCRIPT_UPDATE);
+        if (DEBUGGING) {
+            log_it("told server " + (string)inventory_request_channel + " that i need updating.");
+        }
+    } else {
+        if (DEBUGGING) {
+            log_it("told server " + (string)inventory_request_channel + " that i am done updating.");
+        }
+        llSay(update_channel, DONE_UPDATING);
+    }
+    return TRUE;
+}    
+
+// this alerts the server to our most desired scripts.
+tell_server_our_wish_list()
+{
+    llSay(update_channel, READY_TO_UPDATE + wrap_parameters(updates_needed));
+}
+
+// checks whether all of the updates needed are present yet.
+integer check_on_update_presence()
+{
+    integer indy;
+    for (indy = 0; indy < llGetListLength(updates_needed); indy++) {
+        integer found = find_in_inventory(llList2String(updates_needed, indy), INVENTORY_ALL, TRUE);
+        // any single missing guy means they aren't up to date yet.
+        if (found < 0) {
+            if (DEBUGGING) log_it(llList2String(updates_needed, indy) + " not seen as updated yet.");
+            return FALSE;
+        }
+    }
+    // nothing was detected as missing anymore.
+    return TRUE;
+}
+
+// respond to spoken commands from the server.
+integer process_update_news(integer channel, string name, key id, string message)
+{
+    if (!channel) {
+        // this is a command.
+        if (message == "ureset") {
+            llResetScript();  // start over.
+        }
+        if (message == "ushow") {
+            integer sindy;
+            integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
+            list script_list = [ "scripts--" ];  // first item is just a header.
+            for (sindy = 0; sindy < script_count; sindy++) {
+                script_list += [ llGetInventoryName(INVENTORY_SCRIPT, sindy) ];
+            }
+            dump_list_to_log(script_list);
+        }
+        return FALSE;  // nothing to do here.
+    }
+    if (!update_channel && (channel == UPDATE_ANNOUNCEMENT_CHANNEL)) {
+/* never seen.        if (id == llGetKey()) {
+if (DEBUGGING) log_it("ignoring update from self.");            
+            return FALSE;  // ack, that's our very object.
+        }
+*/
+        if (llStringLength(message) > llStringLength(UPDATE_ANNOUNCEMENT_PREFIX)) {
+            // this is a new style update message.  we can set a different request channel.
+            string just_chan = llDeleteSubString(message, 0, llStringLength(UPDATE_ANNOUNCEMENT_PREFIX) - 1);
+            inventory_request_channel = (integer)just_chan;
+        }
+        integer prev_indy = find_in_list(updaters_heard, id);
+        // find the talker in our list.
+        if (prev_indy >= 0) {
+            // that guy was already heard from.  check when last interacted.
+            integer last_heard = llList2Integer(last_interactions, prev_indy);
+            if (llAbs(llGetUnixTime() - last_heard) < SERVER_IGNORE_TIME) {
+                return FALSE;  // not time to update with this guy again yet.
+            }
+//            if (DEBUGGING) { log_it("started listening again to server " + (string)id); }
+            // make sure we think of this as a new updater now.
+            whack_updater_record(id);
+        }
+
+        if (DEBUGGING) { log_it("heard server " + (string)inventory_request_channel + "'s announcement."); }
+        // record our new server.
+        current_server = id;
+        // make a random pause so not all updaters try to crank up at same time.
+        llSleep(randomize_within_range(2.8, 18.2, FALSE));
+
+        if (llGetListLength(updaters_heard) > MAXIMUM_SERVERS_TRACKED) {
+            // oops, this is not good.  we have too many servers now.
+//hmmm: room for improvement here by tossing out the server that is oldest.
+            updaters_heard = llDeleteSubList(updaters_heard, 0, 0);
+            last_interactions = llDeleteSubList(last_interactions, 0, 0);
+        }
+        
+        // add the talker to our list.
+        updaters_heard += id;
+        last_interactions += llGetUnixTime();
+    
+        // begin the update interaction with this guy.
+        update_channel = random_channel();
+        return TRUE;
+    }
+    if (update_channel && (channel == update_channel) ) {
+        if (is_prefix(message, REPORT_AVAILABLE_SCRIPTS)) {
+            // tasty, this is a list of scripts that can be had.
+            message = llDeleteSubString(message, 0, llStringLength(REPORT_AVAILABLE_SCRIPTS) - 1);
+            if (message == BUSY_BUSY) {
+                // server has signified that it's too busy (or its owner is a moron) because it is
+                // claiming it has no scripts at all.
+                if (DEBUGGING) {
+                    log_it("server " + (string)inventory_request_channel + " is too busy to update us now.");
+                }
+                // make it seem like we need to do this one again sooner than normal.
+                whack_updater_record(id);
+                // busy server means move no further forward.
+                return FALSE;
+            }
+            return initiate_update(message);
+        } else if (is_prefix(message, SHUT_THEM_DOWN)) {
+            if (DEBUGGING) { log_it("stopping other scripts."); }
+            knock_around_other_scripts(FALSE);
+            // now that we know for sure the server's ready to update us,
+            // we tell it what we need.
+            tell_server_our_wish_list();
+            return FALSE;
+        } else if (is_prefix(message, START_THEM_UP)) {
+            // let the server know that we've finished, for all intents and purposes.
+            llSay(update_channel, DONE_UPDATING);
+            // we pause a random bit first; we want to ensure we aren't swamping
+            // SL with our inventory loading.
+            llSleep(randomize_within_range(2.5, 8.2, FALSE));
+            if (DEBUGGING) { log_it("starting other scripts."); }
+            careful_crankup();
+            return TRUE;  // change state now.
+//        } else {
+//log_it("unknown command on update channel: " + message);
+        }
+    }
+    return FALSE;
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    llWhisper(0, llGetScriptName() + " [" + (string)debug_num + "] (" + (string)llGetFreeMemory() + ") " + to_say);
+}
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type, integer exact_match)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (exact_match && (llGetInventoryName(inv_type, inv) == name_to_find) )
+            return inv;
+        else if (!exact_match && is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+//////////////
+
+integer MAX_CHAT_LINE = 900;
+    // the most characters we'll try to say in one chat.
+
+dump_list_to_log(list to_show)
+{
+    string text = dump_list(to_show);  // get some help from the other version.
+    integer len = llStringLength(text);
+    integer i;
+    for (i = 0; i < len; i += MAX_CHAT_LINE) {
+        integer last_bit = i + MAX_CHAT_LINE - 1;
+        if (last_bit >= len) last_bit = len - 1;
+        string next_line = llGetSubString(text, i, last_bit);
+        llWhisper(0, next_line);
+    }
+}
+
+// returns a printable form of the list.
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = 0; i < len; i++) {
+        string next_line = llList2String(to_show, i);
+        if (find_substring(next_line, " ") >= 0) {
+            // this guy has a space in it, so quote it.
+            next_line = "\"" + next_line + "\"";
+        }
+        text = text + next_line;
+        if (i < len - 1) text = text + " ";
+    }
+    return text;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+// no huffotronic trap state for startup, because this script will actually
+// run (and is expected) inside a huffotronic updater object.
+
+default
+{
+    state_entry()
+    {
+        auto_retire();  // only allow the most recent revision.
+        initialize();
+        state awaiting_commands;
+    }
+}
+
+state awaiting_commands
+{
+    state_entry()
+    {
+        if (DEBUGGING) log_it("<awaiting_commands>");
+        careful_crankup();  // we always start by getting everyone running.
+        current_server = NULL_KEY;  // forget previous server.
+        listen_for_orders(FALSE);
+        inventory_request_channel = 0;  // no inventory request channel either.
+        update_channel = 0;  // no channel currently.
+        updates_needed = [];  // we know of no needs right now.
+        known_script_dependencies = [];  // no deps either.
+    }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message))
+            state establish_private_channel;
+    }
+}
+
+state establish_private_channel
+{
+    state_entry()
+    {
+        if (DEBUGGING) log_it("<establish_private_channel>");
+        llListen(update_channel, "", current_server, "");
+        listen_for_orders(TRUE);
+        if (inventory_request_channel)
+            llSay(inventory_request_channel, REQUEST_INVENTORY_PREFIX + (string)update_channel);
+        else
+            llSay(OLD_REQUEST_INVENTORY_CHANNEL, REQUEST_INVENTORY_PREFIX + (string)update_channel);
+        llSetTimerEvent(MAXIMUM_UPDATE_TIME_ALLOWED);
+    }
+
+    state_exit() { llSetTimerEvent(0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message)) {
+            // ready for a state change, but what kind?
+            if (llGetListLength(updates_needed)) {
+//log_it("have a list of updates now.");
+                state performing_update;
+            } else {
+//log_it("no updates needed in list, going back");
+                state awaiting_commands;
+            }
+        }
+    }
+    
+    timer() {
+        if (DEBUGGING) {
+            log_it("timed out establishing channel with server " + (string)inventory_request_channel);
+        }
+        whack_updater_record(current_server);
+        state awaiting_commands;
+    }
+
+    on_rez(integer parm) { state default; }
+}
+
+state performing_update
+{
+    state_entry()
+    {
+        // must re-listen after a state change.
+        llListen(update_channel, "", current_server, "");
+        listen_for_orders(TRUE);
+        if (DEBUGGING) log_it("<performing_update>");
+        llSetTimerEvent(UPDATE_TIMER_INTERVAL);
+        update_start_time = llGetUnixTime();
+    }
+
+    state_exit() { llSetTimerEvent(0.0); }
+
+    listen(integer channel, string name, key id, string message)
+    {
+        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
+            return;  // must be same owner to ensure proper perms.
+        }
+        if (process_update_news(channel, name, id, message)) {
+            // normal finish of update process.
+            state awaiting_commands;
+        }
+    }
+
+    timer() {
+        if (llGetListLength(updates_needed) == 0) {
+//log_it("nothing to update, leaving perform state.");
+            state awaiting_commands;  // we've got nothing to do.
+        } else {
+            // see if all our requested scripts are there yet; if not, we're not done updating.
+            integer ready = check_on_update_presence();
+            if (ready) {
+                if (DEBUGGING) log_it("reporting scripts are current.");
+                llSay(update_channel, SCRIPTS_ARE_CURRENT);
+            }
+        }
+        if (llAbs(update_start_time - llGetUnixTime()) >= MAXIMUM_UPDATE_TIME_ALLOWED) {
+            if (DEBUGGING) { log_it("timeout during update process with server " + (string)inventory_request_channel); }
+            whack_updater_record(current_server);
+            state awaiting_commands;
+        }
+    }
+
+    on_rez(integer parm) { state default; }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/huff-update_client_v20.1.txt b/huffware/huffotronic_updater_freebie_v5.3/huff-update_client_v20.1.txt
deleted file mode 100755 (executable)
index 4a458bb..0000000
+++ /dev/null
@@ -1,826 +0,0 @@
-
-// huffware script: huff-update client, by fred huffhines.
-//
-// this script is the client side of the update process.  it should reside in an object that
-// has scripts which should be automatically updated.  it will listen for announcements by
-// an update server and communicate with the server to ensure that all of its scripts are
-// the most up to date available with the server.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-integer DEBUGGING = FALSE;  // if TRUE, the script will output status information.
-
-integer SERVER_IGNORE_TIME = 1200;  // number of seconds between performing an upgrade with the same server.
-
-integer MAXIMUM_UPDATE_TIME_ALLOWED = 140;  // we allow one upgrade process to take this long overall.
-
-integer UPDATE_ANNOUNCEMENT_CHANNEL   = -420108;  // used by server to brag about itself.
-integer OLD_REQUEST_INVENTORY_CHANNEL = -421008;  // used by clients to request an update list.
-
-string UPDATE_ANNOUNCEMENT_PREFIX   = "#huff-update#";  // first part of any announcement.
-string REQUEST_INVENTORY_PREFIX     = "#huff-reqinv#";  // first part of request for inventory list.
-string REPORT_AVAILABLE_SCRIPTS     = "#scripts#";  // server's keyword to let client know script inventory.
-string REQUEST_SCRIPT_UPDATE        = "#updatego#";  // keyword used by client to request some updates.
-string SHUT_THEM_DOWN               = "#huffdown#";  // server tells client to stop any non-updater scripts.
-string READY_TO_UPDATE              = "#listoneeds#";  // the client tells the server the scripts it wants.
-string SCRIPTS_ARE_CURRENT          = "#gottemthx#";  // client says this when all new scripts are in place.
-string START_THEM_UP                = "#huffup#";  // server tells client to start up other scripts again.
-string DONE_UPDATING                = "#finito#";  // the client is done updating.
-string BUSY_BUSY                    = "#busymuch#";  // a signal that the server is too busy to update us.
-
-float UPDATE_TIMER_INTERVAL = 2.0;  // interval between checks on our update status.
-
-integer UPDATER_SCRIPT_PIN = -1231008;  // the hook for our scripts to be modified.
-
-///float BUSY_SERVER_PAUSE_TIME = 38.0;  // num seconds to delay when server says it's too busy.
-
-string UPDATER_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-
-string SCRIPT_DEPENDENCY_MARK = "DEP";  // signals that a dependency is coming.
-string ITEM_LIST_SEPARATOR = "``";  // separates dependencies.
-
-integer MAXIMUM_SERVERS_TRACKED = 32;
-    // we will listen to this many servers before we decide to remove one.
-
-string CONTINUANCE_MARKER = "...";
-    // a string sent when the update list is too long and needs to be continued in another chat.
-
-string SERVER_SCRIPT = "a huffotronic update server";
-    // the prefix of our server script that hands out updates.
-
-// global variables...
-
-integer inventory_request_channel;  // used for newer version servers to cut down cross chatter.
-list updaters_heard;  // the update servers we've heard from recently.
-list last_interactions;  // times of the last update process engaged with the updater.
-integer update_channel;  // current channel for interaction with specific server.
-key current_server;  // the updater that is active right now, if any.
-integer update_start_time;  // when the last update process began.
-list updates_needed;  // stores the set of scripts that are in need of an update.
-list known_script_dependencies;  // stores the list of dependency info.
-
-careful_crankup()
-{
-    knock_around_other_scripts(TRUE);
-    // clean out the older items and scripts.  we do this after getting everyone running
-    // since we might be whacking ourselves.
-    destroy_older_versions();
-}
-
-// reset our variables.
-initialize()
-{
-    updaters_heard = [];
-    last_interactions = [];
-    inventory_request_channel = 0;
-    update_channel = 0;
-    current_server = NULL_KEY;
-    llSetTimerEvent(0.0);
-    llSetRemoteScriptAccessPin(UPDATER_SCRIPT_PIN);
-    // a new enhancements; tells the server that this guy has finished an update cycle.  this
-    // only comes into play when the updater script itself has just been updated, but it's
-    // nice for the server to avoid claiming erroneous timeouts occurred.
-    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
-    llSleep(0.4);  // snooze and repeat to overcome occasionally lossy chats.
-    llSay(OLD_REQUEST_INVENTORY_CHANNEL, DONE_UPDATING);
-}
-
-whack_updater_record(key id)
-{
-    integer prev_indy = find_in_list(updaters_heard, id);
-    if (prev_indy < 0) return;  // not there.
-    updaters_heard = chop_list(updaters_heard, 0, prev_indy - 1)
-            + chop_list(updaters_heard, prev_indy + 1, llGetListLength(updaters_heard) - 1);
-    last_interactions = chop_list(last_interactions, 0, prev_indy - 1)
-            + chop_list(last_interactions, prev_indy + 1, llGetListLength(last_interactions) - 1);
-}
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        if (DEBUGGING)
-            log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-    // thirdly, try to clean out the notecards.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_NOTECARD);
-}
-
-// sets the object to be listening for update info.
-// if "just_owner" is true, then we will not listen on the general announcement channel.
-listen_for_orders(integer just_owner)
-{
-    if (!just_owner) {
-        // try to hear an update being announced.
-        llListen(UPDATE_ANNOUNCEMENT_CHANNEL, "", NULL_KEY, "");
-    }
-
-    // super secret owner controls.
-    llListen(0, "", llGetOwner(), "");
-}
-
-// returns true if this object is a huffotronic updater of some sort.
-integer inside_of_updater()
-{
-    return find_substring(llGetObjectName(), "huffotronic") >= 0;
-}
-
-// returns true if a script is a version of our update server.
-integer matches_server_script(string to_check)
-{
-    return is_prefix(to_check, SERVER_SCRIPT);
-}
-
-// stops all the scripts besides this one.
-knock_around_other_scripts(integer running_state)
-{
-    integer insider = inside_of_updater();
-    if (running_state == TRUE) {
-        // make sure we crank up the scripts that are new first.  we want to reset them
-        // as well, which we don't want to do for any existing scripts.
-        integer crank_indy;
-        for (crank_indy = 0; crank_indy < llGetListLength(updates_needed); crank_indy++) {
-            string crankee = llList2String(updates_needed, crank_indy);
-            if (find_in_inventory(crankee, INVENTORY_SCRIPT, TRUE) >= 0) {
-                if (!insider || matches_server_script(crankee)) {
-                    // allow it to run again.
-                    llSetScriptState(crankee, TRUE);
-                    // reset it, to make sure it starts at the top.
-                    llResetOtherScript(crankee);
-                }
-            }
-        }
-    }
-
-    integer indy;
-    string self_script = llGetScriptName();
-    // we set all other scripts to the running state requested.
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if ( (curr_script != self_script)
-            && (!insider || matches_server_script(curr_script)) ) {
-            // this one seems ripe for being set to the state requested.
-            llSetScriptState(curr_script, running_state);
-        }
-    }
-}
-
-// a random channel for the interaction with the server.
-integer random_channel() { return -(integer)(llFrand(800000) + 20000); }
-
-// make sure that any dependencies for the script with "basename" are added to the list
-// of requests we make during an update.
-list add_dependencies(string basename)
-{
-    list to_return;
-    integer indy;
-    for (indy = 0; indy < llGetListLength(known_script_dependencies); indy++) {
-        list deps = llParseString2List(llList2String(known_script_dependencies, indy),
-            [ITEM_LIST_SEPARATOR], []);
-//log_it("base=" + llList2String(dep, 0) + " lastver=" + llList2String(dep, 1) + " newdep=" + llList2String(dep, 2));
-        if (basename == llList2String(deps, 0)) {
-            // first off, is this item with new dependencies actually present?
-            integer where = find_in_inventory(basename, INVENTORY_SCRIPT, FALSE);
-            if (where >= 0) {
-                // we do use the script with deps, but is the dependent item really missing?
-                where = find_in_inventory(llList2String(deps, 1), INVENTORY_SCRIPT, FALSE);
-                if (where < 0) {
-                    // we found a dependency match for this script, so we'll ask for the missing item.
-                    if (DEBUGGING)
-                        log_it("missing dep: " + llList2String(deps, 1));
-                    to_return += [ llList2String(deps, 1) ];
-                }
-            }
-        }
-    }
-    return to_return;
-}
-
-// complains if memory seems to be getting tight.
-test_memory()
-{
-    if (llGetFreeMemory() < 4096)
-        log_it("mem_free = " + (string)llGetFreeMemory());
-}
-
-// starts an update given a list of scripts that the server has available, encoded as
-// a string in the "encoded_list".
-integer initiate_update(string encoded_list)
-{
-    list scripts_avail = llParseString2List(encoded_list, [UPDATER_PARM_SEPARATOR], []);
-    integer continue_listening_for_scripts = FALSE;
-      // if true, we aren't done hearing about available scripts yet.
-    encoded_list = "";
-    // figure out which scripts we need by comparing the list available from the server
-    // against our current inventory.  we only want scripts with newer version numbers.
-    integer sindy;
-    for (sindy = 0; sindy < llGetListLength(scripts_avail); sindy++) {
-        string curr = llList2String(scripts_avail, sindy);
-        if (curr == CONTINUANCE_MARKER) {
-            // this is a special continuation signal.  we need to hear the rest of the list.
-            continue_listening_for_scripts = TRUE;
-        } else if (is_prefix(curr, SCRIPT_DEPENDENCY_MARK)) {
-            // we've found a dependency item.
-            known_script_dependencies += [ llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1) ];
-//log_it("script dep: " + llGetSubString(curr, llStringLength(SCRIPT_DEPENDENCY_MARK), -1));
-        } else {
-            list split = compute_basename_and_version(curr);
-            if (llGetListLength(split) == 2) {
-                string basename = llList2String(split, 0);
-                string version = llList2String(split, 1);
-                split = [];
-                integer oy_indy;
-//replace common code with func.
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_OBJECT); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_OBJECT, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-//                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-//                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_NOTECARD); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_NOTECARD, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                for (oy_indy = 0; oy_indy < llGetInventoryNumber(INVENTORY_SCRIPT); oy_indy++) {
-                    list srv_split = compute_basename_and_version
-                        (llGetInventoryName(INVENTORY_SCRIPT, oy_indy));
-                    if ( (llGetListLength(srv_split) == 2)
-                            && (basename == llList2String(srv_split, 0))
-                            && ((float)version > (float)llList2String(srv_split, 1)) ) {
-                        if (DEBUGGING) {
-                            log_it("i need '" + curr + "' from server " + (string)inventory_request_channel);
-                        }
-                        test_memory();
-                        updates_needed += [ curr ];
-                    }
-                }
-                updates_needed += add_dependencies(basename);
-            }
-        }
-    }
-    // we skip the next step if we're still waiting to hear about more.
-    if (continue_listening_for_scripts) {
-//log_it("still listening for more updates...");
-        return FALSE;
-    }
-    if (llGetListLength(updates_needed)) {
-//log_it("update chan=" + (string)update_channel);
-        llSay(update_channel, REQUEST_SCRIPT_UPDATE);
-        if (DEBUGGING) {
-            log_it("told server " + (string)inventory_request_channel + " that i need updating.");
-        }
-    } else {
-        if (DEBUGGING) {
-            log_it("told server " + (string)inventory_request_channel + " that i am done updating.");
-        }
-        llSay(update_channel, DONE_UPDATING);
-    }
-    return TRUE;
-}    
-
-// this alerts the server to our most desired scripts.
-tell_server_our_wish_list()
-{
-    llSay(update_channel, READY_TO_UPDATE + wrap_parameters(updates_needed));
-}
-
-// checks whether all of the updates needed are present yet.
-integer check_on_update_presence()
-{
-    integer indy;
-    for (indy = 0; indy < llGetListLength(updates_needed); indy++) {
-        integer found = find_in_inventory(llList2String(updates_needed, indy), INVENTORY_ALL, TRUE);
-        // any single missing guy means they aren't up to date yet.
-        if (found < 0) {
-            if (DEBUGGING) log_it(llList2String(updates_needed, indy) + " not seen as updated yet.");
-            return FALSE;
-        }
-    }
-    // nothing was detected as missing anymore.
-    return TRUE;
-}
-
-// respond to spoken commands from the server.
-integer process_update_news(integer channel, string name, key id, string message)
-{
-    if (!channel) {
-        // this is a command.
-        if (message == "ureset") {
-            llResetScript();  // start over.
-        }
-        if (message == "ushow") {
-            integer sindy;
-            integer script_count = llGetInventoryNumber(INVENTORY_SCRIPT);
-            list script_list = [ "scripts--" ];  // first item is just a header.
-            for (sindy = 0; sindy < script_count; sindy++) {
-                script_list += [ llGetInventoryName(INVENTORY_SCRIPT, sindy) ];
-            }
-            dump_list_to_log(script_list);
-        }
-        return FALSE;  // nothing to do here.
-    }
-    if (!update_channel && (channel == UPDATE_ANNOUNCEMENT_CHANNEL)) {
-/* never seen.        if (id == llGetKey()) {
-if (DEBUGGING) log_it("ignoring update from self.");            
-            return FALSE;  // ack, that's our very object.
-        }
-*/
-        if (llStringLength(message) > llStringLength(UPDATE_ANNOUNCEMENT_PREFIX)) {
-            // this is a new style update message.  we can set a different request channel.
-            string just_chan = llDeleteSubString(message, 0, llStringLength(UPDATE_ANNOUNCEMENT_PREFIX) - 1);
-            inventory_request_channel = (integer)just_chan;
-        }
-        integer prev_indy = find_in_list(updaters_heard, id);
-        // find the talker in our list.
-        if (prev_indy >= 0) {
-            // that guy was already heard from.  check when last interacted.
-            integer last_heard = llList2Integer(last_interactions, prev_indy);
-            if (llAbs(llGetUnixTime() - last_heard) < SERVER_IGNORE_TIME) {
-                return FALSE;  // not time to update with this guy again yet.
-            }
-//            if (DEBUGGING) { log_it("started listening again to server " + (string)id); }
-            // make sure we think of this as a new updater now.
-            whack_updater_record(id);
-        }
-
-        if (DEBUGGING) { log_it("heard server " + (string)inventory_request_channel + "'s announcement."); }
-        // record our new server.
-        current_server = id;
-        // make a random pause so not all updaters try to crank up at same time.
-        llSleep(randomize_within_range(2.8, 18.2, FALSE));
-
-        if (llGetListLength(updaters_heard) > MAXIMUM_SERVERS_TRACKED) {
-            // oops, this is not good.  we have too many servers now.
-//hmmm: room for improvement here by tossing out the server that is oldest.
-            updaters_heard = llDeleteSubList(updaters_heard, 0, 0);
-            last_interactions = llDeleteSubList(last_interactions, 0, 0);
-        }
-        
-        // add the talker to our list.
-        updaters_heard += id;
-        last_interactions += llGetUnixTime();
-    
-        // begin the update interaction with this guy.
-        update_channel = random_channel();
-        return TRUE;
-    }
-    if (update_channel && (channel == update_channel) ) {
-        if (is_prefix(message, REPORT_AVAILABLE_SCRIPTS)) {
-            // tasty, this is a list of scripts that can be had.
-            message = llDeleteSubString(message, 0, llStringLength(REPORT_AVAILABLE_SCRIPTS) - 1);
-            if (message == BUSY_BUSY) {
-                // server has signified that it's too busy (or its owner is a moron) because it is
-                // claiming it has no scripts at all.
-                if (DEBUGGING) {
-                    log_it("server " + (string)inventory_request_channel + " is too busy to update us now.");
-                }
-                // make it seem like we need to do this one again sooner than normal.
-                whack_updater_record(id);
-                // busy server means move no further forward.
-                return FALSE;
-            }
-            return initiate_update(message);
-        } else if (is_prefix(message, SHUT_THEM_DOWN)) {
-            if (DEBUGGING) { log_it("stopping other scripts."); }
-            knock_around_other_scripts(FALSE);
-            // now that we know for sure the server's ready to update us,
-            // we tell it what we need.
-            tell_server_our_wish_list();
-            return FALSE;
-        } else if (is_prefix(message, START_THEM_UP)) {
-            // let the server know that we've finished, for all intents and purposes.
-            llSay(update_channel, DONE_UPDATING);
-            // we pause a random bit first; we want to ensure we aren't swamping
-            // SL with our inventory loading.
-            llSleep(randomize_within_range(2.5, 8.2, FALSE));
-            if (DEBUGGING) { log_it("starting other scripts."); }
-            careful_crankup();
-            return TRUE;  // change state now.
-//        } else {
-//log_it("unknown command on update channel: " + message);
-        }
-    }
-    return FALSE;
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    llWhisper(0, llGetScriptName() + " [" + (string)debug_num + "] (" + (string)llGetFreeMemory() + ") " + to_say);
-}
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, UPDATER_PARM_SEPARATOR); }
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type, integer exact_match)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (exact_match && (llGetInventoryName(inv_type, inv) == name_to_find) )
-            return inv;
-        else if (!exact_match && is_prefix(llGetInventoryName(inv_type, inv), name_to_find))
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-//////////////
-
-integer MAX_CHAT_LINE = 900;
-    // the most characters we'll try to say in one chat.
-
-dump_list_to_log(list to_show)
-{
-    string text = dump_list(to_show);  // get some help from the other version.
-    integer len = llStringLength(text);
-    integer i;
-    for (i = 0; i < len; i += MAX_CHAT_LINE) {
-        integer last_bit = i + MAX_CHAT_LINE - 1;
-        if (last_bit >= len) last_bit = len - 1;
-        string next_line = llGetSubString(text, i, last_bit);
-        llWhisper(0, next_line);
-    }
-}
-
-// returns a printable form of the list.
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = 0; i < len; i++) {
-        string next_line = llList2String(to_show, i);
-        if (find_substring(next_line, " ") >= 0) {
-            // this guy has a space in it, so quote it.
-            next_line = "\"" + next_line + "\"";
-        }
-        text = text + next_line;
-        if (i < len - 1) text = text + " ";
-    }
-    return text;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-// no huffotronic trap state for startup, because this script will actually
-// run (and is expected) inside a huffotronic updater object.
-
-default
-{
-    state_entry()
-    {
-        auto_retire();  // only allow the most recent revision.
-        initialize();
-        state awaiting_commands;
-    }
-}
-
-state awaiting_commands
-{
-    state_entry()
-    {
-        if (DEBUGGING) log_it("<awaiting_commands>");
-        careful_crankup();  // we always start by getting everyone running.
-        current_server = NULL_KEY;  // forget previous server.
-        listen_for_orders(FALSE);
-        inventory_request_channel = 0;  // no inventory request channel either.
-        update_channel = 0;  // no channel currently.
-        updates_needed = [];  // we know of no needs right now.
-        known_script_dependencies = [];  // no deps either.
-    }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message))
-            state establish_private_channel;
-    }
-}
-
-state establish_private_channel
-{
-    state_entry()
-    {
-        if (DEBUGGING) log_it("<establish_private_channel>");
-        llListen(update_channel, "", current_server, "");
-        listen_for_orders(TRUE);
-        if (inventory_request_channel)
-            llSay(inventory_request_channel, REQUEST_INVENTORY_PREFIX + (string)update_channel);
-        else
-            llSay(OLD_REQUEST_INVENTORY_CHANNEL, REQUEST_INVENTORY_PREFIX + (string)update_channel);
-        llSetTimerEvent(MAXIMUM_UPDATE_TIME_ALLOWED);
-    }
-
-    state_exit() { llSetTimerEvent(0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message)) {
-            // ready for a state change, but what kind?
-            if (llGetListLength(updates_needed)) {
-//log_it("have a list of updates now.");
-                state performing_update;
-            } else {
-//log_it("no updates needed in list, going back");
-                state awaiting_commands;
-            }
-        }
-    }
-    
-    timer() {
-        if (DEBUGGING) {
-            log_it("timed out establishing channel with server " + (string)inventory_request_channel);
-        }
-        whack_updater_record(current_server);
-        state awaiting_commands;
-    }
-
-    on_rez(integer parm) { state default; }
-}
-
-state performing_update
-{
-    state_entry()
-    {
-        // must re-listen after a state change.
-        llListen(update_channel, "", current_server, "");
-        listen_for_orders(TRUE);
-        if (DEBUGGING) log_it("<performing_update>");
-        llSetTimerEvent(UPDATE_TIMER_INTERVAL);
-        update_start_time = llGetUnixTime();
-    }
-
-    state_exit() { llSetTimerEvent(0.0); }
-
-    listen(integer channel, string name, key id, string message)
-    {
-        if ((id != llGetOwner()) && (llGetOwnerKey(id) != llGetOwner())) {
-            return;  // must be same owner to ensure proper perms.
-        }
-        if (process_update_news(channel, name, id, message)) {
-            // normal finish of update process.
-            state awaiting_commands;
-        }
-    }
-
-    timer() {
-        if (llGetListLength(updates_needed) == 0) {
-//log_it("nothing to update, leaving perform state.");
-            state awaiting_commands;  // we've got nothing to do.
-        } else {
-            // see if all our requested scripts are there yet; if not, we're not done updating.
-            integer ready = check_on_update_presence();
-            if (ready) {
-                if (DEBUGGING) log_it("reporting scripts are current.");
-                llSay(update_channel, SCRIPTS_ARE_CURRENT);
-            }
-        }
-        if (llAbs(update_start_time - llGetUnixTime()) >= MAXIMUM_UPDATE_TIME_ALLOWED) {
-            if (DEBUGGING) { log_it("timeout during update process with server " + (string)inventory_request_channel); }
-            whack_updater_record(current_server);
-            state awaiting_commands;
-        }
-    }
-
-    on_rez(integer parm) { state default; }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/hufflets_v6.3.lsl b/huffware/huffotronic_updater_freebie_v5.3/hufflets_v6.3.lsl
new file mode 100755 (executable)
index 0000000..aa9a0e1
--- /dev/null
@@ -0,0 +1,742 @@
+
+// huffware script: hufflets, by fred huffhines.
+//
+// functions that are commonly used but really are too simple to implement via IPC.
+// these just get copied and pasted into other scripts.
+// *note* that means you should not drop this script into an object.  it will not
+// do anything for you.  instead, copy what you need out of here.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer DEBUGGING = FALSE;
+    // if this is set to true, then some functions produce noisier results.
+
+//////////////
+
+// diagnostic hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+//////////////
+
+// mathematical hufflets...
+
+// returns a floating point absolute value.
+float fabs(float take_absolute_value) {
+    if (take_absolute_value >= 0.0) return take_absolute_value;
+    else return -1.0 * take_absolute_value;
+}
+
+//////////////
+
+// time hufflets...
+
+// shows a somewhat pretty printed version of the number of seconds.
+string time_text(integer seconds)
+{
+    float s_min = 60; float s_hour = 60 * s_min; float s_day = 24 * s_hour;
+    float s_year = 365.25 * s_day;
+    
+    if (seconds < s_min) return (string)seconds + " seconds";
+    else if (seconds < s_hour) return float_chop(seconds / s_min) + " minutes";
+    else if (seconds < s_day) return float_chop(seconds / s_hour) + " hours";
+    else if (seconds < s_year) return float_chop(seconds / s_day) + " days";
+    else return float_chop(seconds / s_year) + " years";
+}
+
+//////////////
+
+// string processing hufflets...
+
+// the string processing methods are not case sensitive.
+  
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+// takes any redundant space characters out of the string.
+string compress_spaces(string s)
+{
+    string to_return;
+    integer in_space = FALSE;
+    integer i;
+    for (i = 0; i < llStringLength(s); i++) {
+        string chunk = llGetSubString(s, i, i);
+        if (chunk == " ") {
+            if (in_space) {
+                // we're have already seen a space.  don't keep this too.
+                //continue;  no such keyword in lsl.
+            } else {
+                in_space = TRUE;
+                to_return += chunk;
+            }
+        } else {
+            // the current character was not a space, so just add it.
+            in_space = FALSE;
+            to_return += chunk;
+        }
+    }
+    return to_return;
+}
+
+//////////////
+
+// sim-related hufflets...
+
+// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
+integer valid_sim_value(float to_check)
+{
+    if (to_check < 0.0) return FALSE;
+    if (to_check >= 257.0) return FALSE;
+    return TRUE;
+}
+
+// returns TRUE if the "to_check" vector is a location outside of the current sim.
+integer outside_of_sim(vector to_check)
+{
+    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
+}
+
+//////////////
+
+// list processing hufflets...
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// removes the entry at "index" and instead inserts the list "to_insert"
+// at that position.
+list replace_entry(list to_modify, integer index, list to_insert)
+{
+    if (llGetListLength(to_modify) == 0) return to_insert;  // special case for empty.
+    return llListReplaceList(to_modify, to_insert, index, index);
+}
+
+// returns the portion of the list between start and end, but only if they are
+// valid compared with the list length.  an attempt to use negative start or
+// end values also returns a blank list.
+list chop_list(list to_chop, integer start, integer end)
+{
+    integer last_len = llGetListLength(to_chop) - 1;
+    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
+    return llList2List(to_chop, start, end);
+}
+
+//////////////
+
+integer MAX_CHAT_LINE = 1008;
+    // the most characters we'll try to say in one chat.
+
+dump_list_to_log(list to_show)
+{
+    string text = dump_list(to_show);  // get some help from the other version.
+    integer len = llStringLength(text);
+    integer i;
+    for (i = 0; i < len; i += MAX_CHAT_LINE) {
+        integer last_bit = i + MAX_CHAT_LINE - 1;
+        if (last_bit >= len) last_bit = len - 1;
+        string next_line = llGetSubString(text, i, last_bit);
+        log_it(next_line);
+    }
+}
+
+// returns a printable form of the list.
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = 0; i < len; i++) {
+        string next_line = llList2String(to_show, i);
+        if (find_substring(next_line, " ") >= 0) {
+            // this guy has a space in it, so quote it.
+            next_line = "'" + next_line + "'";
+        }
+        text = text + next_line;
+        if (i < len - 1) text = text + " ";
+    }
+    return text;
+}
+
+// extracts space separated elements from a string, and honors quoting of either
+// variety as long as the quotes come in pairs.  this enables the inclusion of
+// spaces in the elements of the set.  note that this function requires a well-formed
+// string where there are no multiple space characters in a row.
+list parse_quoted_strings(string to_parse)
+{
+    list to_return;  // will pile up what we find in the string.
+    integer quoting = FALSE;  // are we inside quotes?
+    string curr_quote = "";  // what is current quote char, if any?
+    string accum;  // accumulates parts of the current element.
+    // loop over the string and apply our rules.
+    integer i;
+    for (i = 0; i < llStringLength(to_parse); i++) {
+        string c = llGetSubString(to_parse, i, i);
+        if (!quoting && (c == " ")) {
+            // this space marks the end of a word.
+            if (llStringLength(accum) > 0) {
+//log_it("space adding to set: " + accum);
+                to_return += [ accum ];
+                accum = "";
+            }
+        } else if (quoting && (c == curr_quote)) {
+            // done with quotes, so add the quoted item, even if nil.
+            to_return += [ accum ];
+//log_it("quote adding to set: " + accum);
+            accum = "";
+            quoting = FALSE;
+        } else if (!quoting && ( (c == "'") || (c == "\"") ) ) {
+            // we've started into quoting mode.
+            quoting = TRUE;
+            curr_quote = c;
+        } else {
+            // if no condition applies, just add this to the accumulator.
+            accum += c;
+        }
+    }
+    // add the last thing we accumulated.
+    if (llStringLength(accum) > 0) {
+//log_it("last add to set: " + accum);
+        to_return += [ accum ];
+    }
+    return to_return;
+}
+
+//////////////
+
+// action queue for postponed activities.  the first field held in a list item here
+// is an integer action code.  the format of the remaining parameters is up to the
+// caller, and they can be used as the final parameters for when the queued action
+// gets handled.
+list action_queue;
+
+// looks at the action code at the head of the queue without removing the action.
+integer peek_action_code()
+{
+    list fields = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
+    return extract_action_code(fields);
+}
+
+// extracts the action code from a retrieved list.
+integer extract_action_code(list to_parse) { return llList2Integer(to_parse, 0); }
+
+// removes the current head of the action queue and returns it.
+list pop_action_record()
+{
+    if (llGetListLength(action_queue) == 0) {
+//log_it("failure in action q: no entries.");
+        return [];
+    }
+    list top_action = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
+    action_queue = llDeleteSubList(action_queue, 0, 0);
+    return top_action;
+}
+
+// adds a new action to the end of the action queue.
+push_action_record(integer action, list added_parms)
+{
+    action_queue += [ wrap_parameters([action] + added_parms) ];
+}
+
+//////////////
+
+// randomizing hufflets...
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+//////////////
+
+// vector hufflets...
+
+// returns TRUE if a is less than b in any component.
+integer vector_less_than(vector a, vector b)
+{ return (a.x < b.x) || (a.y < b.y) || (a.z < b.z); }
+
+// returns TRUE if a is greater than b in any component.
+integer vector_greater_than(vector a, vector b)
+{ return (a.x > b.x) || (a.y > b.y) || (a.z > b.z); }
+
+// returns text for a floating point number, but includes only
+// three digits after the decimal point.
+string float_chop(float to_show)
+{
+    integer mant = llAbs(llRound(to_show * 1000.0) / 1000);
+    string neg_sign;
+    if (to_show < 0.0) neg_sign = "-";
+    string dec_s = (string)((llRound(to_show * 1000.0) - mant * 1000) / 1000.0);
+    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
+    // strip off all trailing zeros.
+    while (llGetSubString(dec_s, -1, -1) == "0")
+        dec_s = llDeleteSubString(dec_s, -1, -1);
+    string to_return = neg_sign + (string)mant;
+    if (llStringLength(dec_s)) to_return += "." + dec_s;
+    return to_return;
+}
+
+// returns a prettier form for vector text, with chopped floats.
+string vector_chop(vector to_show)
+{
+    return "<" + float_chop(to_show.x) + ","
+        + float_chop(to_show.y) + ","
+        + float_chop(to_show.z) + ">";
+}
+
+// prints the list of vectors with trimmed floats.
+string vector_list_chop(list to_show)
+{
+    integer list_len = llGetListLength(to_show);
+    string to_return;
+    integer indy;
+    for (indy = 0; indy < list_len; indy++) {
+        if (indy != 0) to_return += HUFFWARE_ITEM_SEPARATOR;
+        to_return += vector_chop((vector)llList2String(to_show, indy));
+    }
+    return to_return;
+}
+
+// returns a list with two components; a new vector and a boolean.
+// the new vector starts from "starting_point".  it will have a vector
+// between "minimum_addition" and "maximum_addition" added to it.
+// if it is over the "minimum_allowed" or the "maximum_allowed", then
+// it is reset to whichever it would have crossed over.  two booleans
+// are also returned to indicate when the lower and upper limits were
+// exceeded (in that order).
+list limit_and_add(vector starting_point,
+    vector minimum_allowed, vector maximum_allowed,
+    vector minimum_addition, vector maximum_addition)
+{
+    integer too_low = FALSE;
+    integer too_high = FALSE;
+    vector new_location = starting_point;
+    vector addition = random_bound_vector(minimum_addition, maximum_addition, FALSE);
+//log_it("start=" + (string)starting_point + " addin=" + (string)addition);
+    new_location += addition;
+    if (vector_less_than(new_location, minimum_allowed)) {
+        too_low = TRUE;
+        new_location = minimum_allowed;
+    } else if (vector_greater_than(new_location, maximum_allowed)) {
+        too_high = TRUE;
+        new_location = maximum_allowed;
+    }
+    return [ new_location, too_low, too_high ];
+}
+
+//////////////
+
+// SL name hufflets...
+
+// returns the position of the last space in "look_within" or a negative number.
+integer find_last_space(string look_within)
+{
+    integer indy = llStringLength(look_within) - 1;
+    while ( (indy >= 0) && (llGetSubString(look_within, indy, indy) != " ") ) indy--;
+    return indy;
+}
+
+// returns the first name for an avatar with the "full_name".
+string first_name(string full_name)
+{
+    integer finding = find_last_space(full_name);
+    if (finding >= 0) return llGetSubString(full_name, 0, finding - 1);
+    return full_name;  // failed to find space.
+}
+
+// returns the last name for an avatar with the "full_name".
+string last_name(string full_name)
+{
+    integer finding = find_last_space(full_name);
+    if (finding >= 0) return llGetSubString(full_name, finding + 1, -1);
+    return full_name;  // failed to find space.
+}
+
+//////////////
+
+// variable handling hufflets...
+
+// substitutes a variable's name for its value.  note that variables are assumed to start
+// with a dollar sign character, which should not be provided in the "variable_name" parameter.
+string substitute_variable(string substitute_within, string variable_name, string variable_value)
+{
+    string to_return = substitute_within;
+//log_it("before var sub: " + substitute_within);
+    integer posn;
+    while ( (posn = find_substring(to_return, "$" + variable_name)) >= 0) {
+        // we found an occurrence of the variable.
+        to_return = llDeleteSubString(to_return, posn, -1)  // keep part before.
+            + variable_value  // add the value in place of the variable name.
+            + llDeleteSubString(to_return, 0, posn + llStringLength(variable_name));
+                // keep part after.
+    }
+//log_it("after var sub: " + to_return);
+    return to_return;
+}
+
+// in "substitute_within", this finds any occurrences of items in the "variables_names"
+// and replaces those with the corresponding item from "variable_values".
+// note: this can be very stack intensive, so it might be better just to use multiple
+// calls to the substitute_variable function.
+string substitute_variable_list(string substitute_within, list variable_names, list variable_values)
+{
+    string to_return = substitute_within;
+    integer vars = llGetListLength(variable_names);
+    if (vars != llGetListLength(variable_values)) {
+        log_it("error in substitute_variable_list: inequal number of variable names vs. values.");
+        return to_return;
+    }
+    integer indy;
+    for (indy = 0; indy < vars; indy++) {
+        to_return = substitute_variable(to_return,
+            llList2String(variable_names, indy),
+            llList2String(variable_values, indy));
+    }
+    return to_return;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+    return [ llStringTrim(x, STRING_TRIM), llStringTrim(y, STRING_TRIM) ];
+}
+
+// returns a non-empty string if "to_check" defines a value for "variable_name".
+// this must be in the form "X=Y", where X is the variable_name and Y is the value.
+string get_variable_value(string to_check, string variable_name)
+{
+    list x_y = separate_variable_definition(to_check);
+    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
+    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
+    return llList2String(x_y, 1);  // a match!
+}
+
+//////////////
+
+// inventory hufflets...
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (llGetInventoryName(inv_type, inv) == name_to_find)
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+
+// looks for an inventory item with the same prefix as the "basename_to_seek".
+integer find_basename_in_inventory(string basename_to_seek, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer indy;
+    for (indy = 0; indy < num_inv; indy++) {
+        if (is_prefix(llGetInventoryName(inv_type, indy), basename_to_seek))
+            return indy;
+    }
+    return -2;  // failed to find it.
+}
+
+//////////////
+//
+// imported from auto-retire, which is the official source!...
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+        log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+destroy_older_versions()
+{
+    // firstly, iterate across scripts to clean out older versions.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
+    // secondly, try to clean out the objects.
+    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
+}
+
+//////////////
+
+// interprocess communication hufflets...  i.e., IPC parts.
+
+// a repository for commonly used inter-process communication (IPC) source
+// code.  hopefully in the future this will be worthwhile coming to first,
+// when a new link message API is being built.
+
+// an example link message API...
+//////////////
+integer SERVICE_X_HUFFWARE_ID = -14000;
+    // a unique ID within the huffware system for this script.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+//////////////
+
+// then the main body of IPC support functions.
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+
+// handles when blank strings need to come through the pipe.
+string wrap_blank_string(string to_wrap)
+{
+    if (llStringLength(to_wrap)) return to_wrap;  // that one is okay.
+    return "\"\"";  // return a quoted nothing as a signal for a blank.
+}
+
+// undoes a previously wrapped blank string.
+string interpret_blank_string(string to_unwrap)
+{
+    if (to_unwrap == "\"\"") return "";  // that was an encoded blank.
+    return to_unwrap;  // no encoding.
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply(integer destination, list parms, string command)
+{
+    llMessageLinked(destination, SERVICE_X_HUFFWARE_ID + REPLY_DISTANCE, command,
+        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+// this should be invoked from the link_message event handler to process the requests
+// for whatever service this library script provides.
+handle_link_message(integer sender, integer huff_id, string msg, key id)
+{
+log_it("link msg: " + (string)sender + " " + (string)huff_id + " msg=" + msg + " id=" + (string)id);
+    // this check is more for the server; the server should listen on the main huffware id.
+    if (huff_id != SERVICE_X_HUFFWARE_ID) {
+        // the check below would make more sense in the client; it should listen on huffware id + REPLY_DISTANCE.
+        if (huff_id != SERVICE_X_HUFFWARE_ID + REPLY_DISTANCE) return;  // totally not for us.
+        // this is a reply to a previous request.
+        if (msg == "moobert") {
+            // handle the response.
+        }
+        // done with reply handling.
+        return;
+    }
+    // separate the list out
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    
+    //example usage of parsed pieces.
+    key k = (key)llList2String(parms, 0);
+    string s = interpret_blank_string(llList2String(parms, 1));
+    integer i = (integer)llList2String(parms, 2);
+    vector v = (vector)llList2String(parms, 3);
+    
+    // we interpret the "msg" as a command.  the "id" has extra parameters.
+    if (msg == "unflux") {
+        // do something
+    }
+}
+
+//////////////
+
+// graphical hufflets...
+
+// a replacement for the deprecated llMakeExplosion function; this bangs the
+// "texture" out as a particle with the "size" in meters.  the number of 
+// particles in a burst is passed in "particle_count".  the function will
+// generate a timer event after "timeout" seconds (pass zero for no timeout).
+make_explosion(string texture, vector size, integer particle_count,
+    float timeout)
+{
+    llParticleSystem([PSYS_PART_FLAGS, PSYS_PART_WIND_MASK | PSYS_PART_EMISSIVE_MASK,
+        PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE,
+        PSYS_PART_START_SCALE, size,
+        PSYS_PART_END_SCALE, size,
+        PSYS_SRC_BURST_PART_COUNT, particle_count,
+        PSYS_PART_MAX_AGE, 2,
+        PSYS_SRC_TEXTURE, texture]);
+    llSetTimerEvent(timeout);
+}
+// the event handler for the particle system to be shut down again.
+//timer() { llParticleSystem([]); }
+
+//////////////
+
+// the following state mumbo jumbo is so that our scripts do not go crazy when the huffotronic
+// updater is rezzed.  that device has most of our scripts in it, and cannot always crush their
+// state fast enough to stop them all.
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        log_it("memory left " + (string)llGetFreeMemory());
+    }
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/hufflets_v6.3.txt b/huffware/huffotronic_updater_freebie_v5.3/hufflets_v6.3.txt
deleted file mode 100755 (executable)
index aa9a0e1..0000000
+++ /dev/null
@@ -1,742 +0,0 @@
-
-// huffware script: hufflets, by fred huffhines.
-//
-// functions that are commonly used but really are too simple to implement via IPC.
-// these just get copied and pasted into other scripts.
-// *note* that means you should not drop this script into an object.  it will not
-// do anything for you.  instead, copy what you need out of here.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer DEBUGGING = FALSE;
-    // if this is set to true, then some functions produce noisier results.
-
-//////////////
-
-// diagnostic hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-//////////////
-
-// mathematical hufflets...
-
-// returns a floating point absolute value.
-float fabs(float take_absolute_value) {
-    if (take_absolute_value >= 0.0) return take_absolute_value;
-    else return -1.0 * take_absolute_value;
-}
-
-//////////////
-
-// time hufflets...
-
-// shows a somewhat pretty printed version of the number of seconds.
-string time_text(integer seconds)
-{
-    float s_min = 60; float s_hour = 60 * s_min; float s_day = 24 * s_hour;
-    float s_year = 365.25 * s_day;
-    
-    if (seconds < s_min) return (string)seconds + " seconds";
-    else if (seconds < s_hour) return float_chop(seconds / s_min) + " minutes";
-    else if (seconds < s_day) return float_chop(seconds / s_hour) + " hours";
-    else if (seconds < s_year) return float_chop(seconds / s_day) + " days";
-    else return float_chop(seconds / s_year) + " years";
-}
-
-//////////////
-
-// string processing hufflets...
-
-// the string processing methods are not case sensitive.
-  
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-// takes any redundant space characters out of the string.
-string compress_spaces(string s)
-{
-    string to_return;
-    integer in_space = FALSE;
-    integer i;
-    for (i = 0; i < llStringLength(s); i++) {
-        string chunk = llGetSubString(s, i, i);
-        if (chunk == " ") {
-            if (in_space) {
-                // we're have already seen a space.  don't keep this too.
-                //continue;  no such keyword in lsl.
-            } else {
-                in_space = TRUE;
-                to_return += chunk;
-            }
-        } else {
-            // the current character was not a space, so just add it.
-            in_space = FALSE;
-            to_return += chunk;
-        }
-    }
-    return to_return;
-}
-
-//////////////
-
-// sim-related hufflets...
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-// returns TRUE if the "to_check" vector is a location outside of the current sim.
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-//////////////
-
-// list processing hufflets...
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// removes the entry at "index" and instead inserts the list "to_insert"
-// at that position.
-list replace_entry(list to_modify, integer index, list to_insert)
-{
-    if (llGetListLength(to_modify) == 0) return to_insert;  // special case for empty.
-    return llListReplaceList(to_modify, to_insert, index, index);
-}
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-//////////////
-
-integer MAX_CHAT_LINE = 1008;
-    // the most characters we'll try to say in one chat.
-
-dump_list_to_log(list to_show)
-{
-    string text = dump_list(to_show);  // get some help from the other version.
-    integer len = llStringLength(text);
-    integer i;
-    for (i = 0; i < len; i += MAX_CHAT_LINE) {
-        integer last_bit = i + MAX_CHAT_LINE - 1;
-        if (last_bit >= len) last_bit = len - 1;
-        string next_line = llGetSubString(text, i, last_bit);
-        log_it(next_line);
-    }
-}
-
-// returns a printable form of the list.
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = 0; i < len; i++) {
-        string next_line = llList2String(to_show, i);
-        if (find_substring(next_line, " ") >= 0) {
-            // this guy has a space in it, so quote it.
-            next_line = "'" + next_line + "'";
-        }
-        text = text + next_line;
-        if (i < len - 1) text = text + " ";
-    }
-    return text;
-}
-
-// extracts space separated elements from a string, and honors quoting of either
-// variety as long as the quotes come in pairs.  this enables the inclusion of
-// spaces in the elements of the set.  note that this function requires a well-formed
-// string where there are no multiple space characters in a row.
-list parse_quoted_strings(string to_parse)
-{
-    list to_return;  // will pile up what we find in the string.
-    integer quoting = FALSE;  // are we inside quotes?
-    string curr_quote = "";  // what is current quote char, if any?
-    string accum;  // accumulates parts of the current element.
-    // loop over the string and apply our rules.
-    integer i;
-    for (i = 0; i < llStringLength(to_parse); i++) {
-        string c = llGetSubString(to_parse, i, i);
-        if (!quoting && (c == " ")) {
-            // this space marks the end of a word.
-            if (llStringLength(accum) > 0) {
-//log_it("space adding to set: " + accum);
-                to_return += [ accum ];
-                accum = "";
-            }
-        } else if (quoting && (c == curr_quote)) {
-            // done with quotes, so add the quoted item, even if nil.
-            to_return += [ accum ];
-//log_it("quote adding to set: " + accum);
-            accum = "";
-            quoting = FALSE;
-        } else if (!quoting && ( (c == "'") || (c == "\"") ) ) {
-            // we've started into quoting mode.
-            quoting = TRUE;
-            curr_quote = c;
-        } else {
-            // if no condition applies, just add this to the accumulator.
-            accum += c;
-        }
-    }
-    // add the last thing we accumulated.
-    if (llStringLength(accum) > 0) {
-//log_it("last add to set: " + accum);
-        to_return += [ accum ];
-    }
-    return to_return;
-}
-
-//////////////
-
-// action queue for postponed activities.  the first field held in a list item here
-// is an integer action code.  the format of the remaining parameters is up to the
-// caller, and they can be used as the final parameters for when the queued action
-// gets handled.
-list action_queue;
-
-// looks at the action code at the head of the queue without removing the action.
-integer peek_action_code()
-{
-    list fields = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
-    return extract_action_code(fields);
-}
-
-// extracts the action code from a retrieved list.
-integer extract_action_code(list to_parse) { return llList2Integer(to_parse, 0); }
-
-// removes the current head of the action queue and returns it.
-list pop_action_record()
-{
-    if (llGetListLength(action_queue) == 0) {
-//log_it("failure in action q: no entries.");
-        return [];
-    }
-    list top_action = llParseString2List(llList2String(action_queue, 0), [HUFFWARE_PARM_SEPARATOR], []);
-    action_queue = llDeleteSubList(action_queue, 0, 0);
-    return top_action;
-}
-
-// adds a new action to the end of the action queue.
-push_action_record(integer action, list added_parms)
-{
-    action_queue += [ wrap_parameters([action] + added_parms) ];
-}
-
-//////////////
-
-// randomizing hufflets...
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-//////////////
-
-// vector hufflets...
-
-// returns TRUE if a is less than b in any component.
-integer vector_less_than(vector a, vector b)
-{ return (a.x < b.x) || (a.y < b.y) || (a.z < b.z); }
-
-// returns TRUE if a is greater than b in any component.
-integer vector_greater_than(vector a, vector b)
-{ return (a.x > b.x) || (a.y > b.y) || (a.z > b.z); }
-
-// returns text for a floating point number, but includes only
-// three digits after the decimal point.
-string float_chop(float to_show)
-{
-    integer mant = llAbs(llRound(to_show * 1000.0) / 1000);
-    string neg_sign;
-    if (to_show < 0.0) neg_sign = "-";
-    string dec_s = (string)((llRound(to_show * 1000.0) - mant * 1000) / 1000.0);
-    dec_s = llGetSubString(llGetSubString(dec_s, find_substring(dec_s, ".") + 1, -1), 0, 2);
-    // strip off all trailing zeros.
-    while (llGetSubString(dec_s, -1, -1) == "0")
-        dec_s = llDeleteSubString(dec_s, -1, -1);
-    string to_return = neg_sign + (string)mant;
-    if (llStringLength(dec_s)) to_return += "." + dec_s;
-    return to_return;
-}
-
-// returns a prettier form for vector text, with chopped floats.
-string vector_chop(vector to_show)
-{
-    return "<" + float_chop(to_show.x) + ","
-        + float_chop(to_show.y) + ","
-        + float_chop(to_show.z) + ">";
-}
-
-// prints the list of vectors with trimmed floats.
-string vector_list_chop(list to_show)
-{
-    integer list_len = llGetListLength(to_show);
-    string to_return;
-    integer indy;
-    for (indy = 0; indy < list_len; indy++) {
-        if (indy != 0) to_return += HUFFWARE_ITEM_SEPARATOR;
-        to_return += vector_chop((vector)llList2String(to_show, indy));
-    }
-    return to_return;
-}
-
-// returns a list with two components; a new vector and a boolean.
-// the new vector starts from "starting_point".  it will have a vector
-// between "minimum_addition" and "maximum_addition" added to it.
-// if it is over the "minimum_allowed" or the "maximum_allowed", then
-// it is reset to whichever it would have crossed over.  two booleans
-// are also returned to indicate when the lower and upper limits were
-// exceeded (in that order).
-list limit_and_add(vector starting_point,
-    vector minimum_allowed, vector maximum_allowed,
-    vector minimum_addition, vector maximum_addition)
-{
-    integer too_low = FALSE;
-    integer too_high = FALSE;
-    vector new_location = starting_point;
-    vector addition = random_bound_vector(minimum_addition, maximum_addition, FALSE);
-//log_it("start=" + (string)starting_point + " addin=" + (string)addition);
-    new_location += addition;
-    if (vector_less_than(new_location, minimum_allowed)) {
-        too_low = TRUE;
-        new_location = minimum_allowed;
-    } else if (vector_greater_than(new_location, maximum_allowed)) {
-        too_high = TRUE;
-        new_location = maximum_allowed;
-    }
-    return [ new_location, too_low, too_high ];
-}
-
-//////////////
-
-// SL name hufflets...
-
-// returns the position of the last space in "look_within" or a negative number.
-integer find_last_space(string look_within)
-{
-    integer indy = llStringLength(look_within) - 1;
-    while ( (indy >= 0) && (llGetSubString(look_within, indy, indy) != " ") ) indy--;
-    return indy;
-}
-
-// returns the first name for an avatar with the "full_name".
-string first_name(string full_name)
-{
-    integer finding = find_last_space(full_name);
-    if (finding >= 0) return llGetSubString(full_name, 0, finding - 1);
-    return full_name;  // failed to find space.
-}
-
-// returns the last name for an avatar with the "full_name".
-string last_name(string full_name)
-{
-    integer finding = find_last_space(full_name);
-    if (finding >= 0) return llGetSubString(full_name, finding + 1, -1);
-    return full_name;  // failed to find space.
-}
-
-//////////////
-
-// variable handling hufflets...
-
-// substitutes a variable's name for its value.  note that variables are assumed to start
-// with a dollar sign character, which should not be provided in the "variable_name" parameter.
-string substitute_variable(string substitute_within, string variable_name, string variable_value)
-{
-    string to_return = substitute_within;
-//log_it("before var sub: " + substitute_within);
-    integer posn;
-    while ( (posn = find_substring(to_return, "$" + variable_name)) >= 0) {
-        // we found an occurrence of the variable.
-        to_return = llDeleteSubString(to_return, posn, -1)  // keep part before.
-            + variable_value  // add the value in place of the variable name.
-            + llDeleteSubString(to_return, 0, posn + llStringLength(variable_name));
-                // keep part after.
-    }
-//log_it("after var sub: " + to_return);
-    return to_return;
-}
-
-// in "substitute_within", this finds any occurrences of items in the "variables_names"
-// and replaces those with the corresponding item from "variable_values".
-// note: this can be very stack intensive, so it might be better just to use multiple
-// calls to the substitute_variable function.
-string substitute_variable_list(string substitute_within, list variable_names, list variable_values)
-{
-    string to_return = substitute_within;
-    integer vars = llGetListLength(variable_names);
-    if (vars != llGetListLength(variable_values)) {
-        log_it("error in substitute_variable_list: inequal number of variable names vs. values.");
-        return to_return;
-    }
-    integer indy;
-    for (indy = 0; indy < vars; indy++) {
-        to_return = substitute_variable(to_return,
-            llList2String(variable_names, indy),
-            llList2String(variable_values, indy));
-    }
-    return to_return;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-    return [ llStringTrim(x, STRING_TRIM), llStringTrim(y, STRING_TRIM) ];
-}
-
-// returns a non-empty string if "to_check" defines a value for "variable_name".
-// this must be in the form "X=Y", where X is the variable_name and Y is the value.
-string get_variable_value(string to_check, string variable_name)
-{
-    list x_y = separate_variable_definition(to_check);
-    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
-    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
-    return llList2String(x_y, 1);  // a match!
-}
-
-//////////////
-
-// inventory hufflets...
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (llGetInventoryName(inv_type, inv) == name_to_find)
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-
-// looks for an inventory item with the same prefix as the "basename_to_seek".
-integer find_basename_in_inventory(string basename_to_seek, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer indy;
-    for (indy = 0; indy < num_inv; indy++) {
-        if (is_prefix(llGetInventoryName(inv_type, indy), basename_to_seek))
-            return indy;
-    }
-    return -2;  // failed to find it.
-}
-
-//////////////
-//
-// imported from auto-retire, which is the official source!...
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-        log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-destroy_older_versions()
-{
-    // firstly, iterate across scripts to clean out older versions.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_SCRIPT);
-    // secondly, try to clean out the objects.
-    scrub_items_by_type(llGetScriptName(), INVENTORY_OBJECT);
-}
-
-//////////////
-
-// interprocess communication hufflets...  i.e., IPC parts.
-
-// a repository for commonly used inter-process communication (IPC) source
-// code.  hopefully in the future this will be worthwhile coming to first,
-// when a new link message API is being built.
-
-// an example link message API...
-//////////////
-integer SERVICE_X_HUFFWARE_ID = -14000;
-    // a unique ID within the huffware system for this script.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-//////////////
-
-// then the main body of IPC support functions.
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-
-// handles when blank strings need to come through the pipe.
-string wrap_blank_string(string to_wrap)
-{
-    if (llStringLength(to_wrap)) return to_wrap;  // that one is okay.
-    return "\"\"";  // return a quoted nothing as a signal for a blank.
-}
-
-// undoes a previously wrapped blank string.
-string interpret_blank_string(string to_unwrap)
-{
-    if (to_unwrap == "\"\"") return "";  // that was an encoded blank.
-    return to_unwrap;  // no encoding.
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply(integer destination, list parms, string command)
-{
-    llMessageLinked(destination, SERVICE_X_HUFFWARE_ID + REPLY_DISTANCE, command,
-        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-// this should be invoked from the link_message event handler to process the requests
-// for whatever service this library script provides.
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-log_it("link msg: " + (string)sender + " " + (string)huff_id + " msg=" + msg + " id=" + (string)id);
-    // this check is more for the server; the server should listen on the main huffware id.
-    if (huff_id != SERVICE_X_HUFFWARE_ID) {
-        // the check below would make more sense in the client; it should listen on huffware id + REPLY_DISTANCE.
-        if (huff_id != SERVICE_X_HUFFWARE_ID + REPLY_DISTANCE) return;  // totally not for us.
-        // this is a reply to a previous request.
-        if (msg == "moobert") {
-            // handle the response.
-        }
-        // done with reply handling.
-        return;
-    }
-    // separate the list out
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    
-    //example usage of parsed pieces.
-    key k = (key)llList2String(parms, 0);
-    string s = interpret_blank_string(llList2String(parms, 1));
-    integer i = (integer)llList2String(parms, 2);
-    vector v = (vector)llList2String(parms, 3);
-    
-    // we interpret the "msg" as a command.  the "id" has extra parameters.
-    if (msg == "unflux") {
-        // do something
-    }
-}
-
-//////////////
-
-// graphical hufflets...
-
-// a replacement for the deprecated llMakeExplosion function; this bangs the
-// "texture" out as a particle with the "size" in meters.  the number of 
-// particles in a burst is passed in "particle_count".  the function will
-// generate a timer event after "timeout" seconds (pass zero for no timeout).
-make_explosion(string texture, vector size, integer particle_count,
-    float timeout)
-{
-    llParticleSystem([PSYS_PART_FLAGS, PSYS_PART_WIND_MASK | PSYS_PART_EMISSIVE_MASK,
-        PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE,
-        PSYS_PART_START_SCALE, size,
-        PSYS_PART_END_SCALE, size,
-        PSYS_SRC_BURST_PART_COUNT, particle_count,
-        PSYS_PART_MAX_AGE, 2,
-        PSYS_SRC_TEXTURE, texture]);
-    llSetTimerEvent(timeout);
-}
-// the event handler for the particle system to be shut down again.
-//timer() { llParticleSystem([]); }
-
-//////////////
-
-// the following state mumbo jumbo is so that our scripts do not go crazy when the huffotronic
-// updater is rezzed.  that device has most of our scripts in it, and cannot always crush their
-// state fast enough to stop them all.
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        log_it("memory left " + (string)llGetFreeMemory());
-    }
-}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/huffware_id_registry_v3.2.lsl b/huffware/huffotronic_updater_freebie_v5.3/huffware_id_registry_v3.2.lsl
new file mode 100755 (executable)
index 0000000..d2bd4e6
--- /dev/null
@@ -0,0 +1,44 @@
+
+linked message IDs used already:
+
+    10008 jaunter library - teleportation and physics helper methods.
+    10009 menutini library - a menuing system for requesting input from the avatar.
+    10010 noteworthy library - reads notecards with a specific signature.
+    10011 sitting script - alerts when avatar sits down.
+    10012 remotely personable - can be told what text label to show and when to hide itself, plus *dancing*.
+    10013 hud manager - can control the hud links at behest of other scripts.
+    10014 sensor plugin - runs a hud manager by putting names of avatars up on buttons.
+    10015 hud configurator - loads a configuration file for the HUD it lives in.
+    10016 hud menu manager - accepts a set of menus and customizes them to the avatar.
+    10017 data cow - manages a list of text.
+    10018 party culiar particle system.
+    10019 hud substituter - replaces patterns inside strings for the hud.
+    10020 set comparator - provides operations on sets.
+    10021 inventory exchanger - allows a root prim to keep its child prims synched.
+    10022 jaunt configuration - a split piece of jaunt wik rez that handles config.
+    10023 avatar timer manager - tracks time available to an avatar and generates alerts.
+    10024 change click action - makes the object behave differently when clicked.
+    10025 jaunt rezolator - handling of children rezzed by root jaunter.
+    10026 avatar choice memory - tracks which items an avatar has already chosen.
+    10027 viewscreen blitter - handles requests to show URLs and textures in opensim.
+    10028 slate reader - manages notecards filled with readable information.
+    10029 jaunter button pusher - specialized button pusher for jaunter-style teleporters.
+    10030 sound player - triggers the playing of sound files from inventory.
+    10031 animote configula - ejected configuration and menu functions to reduce memory usage.
+    10032 huff-search pointer - supports searchbert and other search engines.
+    10033 menu list manager - generalized management of a collection of menus.
+    10034 searchbert menus - controller actions for searchbert's menu system.
+    10035 general button pusher - used by prim buttons to signal that they have been clicked.
+    ...
+    10042 card configurator - uses noteworthy to process notecards into lists of configuration items.
+
+script pins in use, at the moment:
+    -100008 unused?
+
+reply distance:
+    REPLY_DISTANCE = 100008
+    this amount is added to the huffware ID to get the reply ID of the service.
+
+on rez IDs for communicating information to created object:
+    10008 auto-rez jaunter startup code
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/huffware_id_registry_v3.2.txt b/huffware/huffotronic_updater_freebie_v5.3/huffware_id_registry_v3.2.txt
deleted file mode 100755 (executable)
index d2bd4e6..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-
-linked message IDs used already:
-
-    10008 jaunter library - teleportation and physics helper methods.
-    10009 menutini library - a menuing system for requesting input from the avatar.
-    10010 noteworthy library - reads notecards with a specific signature.
-    10011 sitting script - alerts when avatar sits down.
-    10012 remotely personable - can be told what text label to show and when to hide itself, plus *dancing*.
-    10013 hud manager - can control the hud links at behest of other scripts.
-    10014 sensor plugin - runs a hud manager by putting names of avatars up on buttons.
-    10015 hud configurator - loads a configuration file for the HUD it lives in.
-    10016 hud menu manager - accepts a set of menus and customizes them to the avatar.
-    10017 data cow - manages a list of text.
-    10018 party culiar particle system.
-    10019 hud substituter - replaces patterns inside strings for the hud.
-    10020 set comparator - provides operations on sets.
-    10021 inventory exchanger - allows a root prim to keep its child prims synched.
-    10022 jaunt configuration - a split piece of jaunt wik rez that handles config.
-    10023 avatar timer manager - tracks time available to an avatar and generates alerts.
-    10024 change click action - makes the object behave differently when clicked.
-    10025 jaunt rezolator - handling of children rezzed by root jaunter.
-    10026 avatar choice memory - tracks which items an avatar has already chosen.
-    10027 viewscreen blitter - handles requests to show URLs and textures in opensim.
-    10028 slate reader - manages notecards filled with readable information.
-    10029 jaunter button pusher - specialized button pusher for jaunter-style teleporters.
-    10030 sound player - triggers the playing of sound files from inventory.
-    10031 animote configula - ejected configuration and menu functions to reduce memory usage.
-    10032 huff-search pointer - supports searchbert and other search engines.
-    10033 menu list manager - generalized management of a collection of menus.
-    10034 searchbert menus - controller actions for searchbert's menu system.
-    10035 general button pusher - used by prim buttons to signal that they have been clicked.
-    ...
-    10042 card configurator - uses noteworthy to process notecards into lists of configuration items.
-
-script pins in use, at the moment:
-    -100008 unused?
-
-reply distance:
-    REPLY_DISTANCE = 100008
-    this amount is added to the huffware ID to get the reply ID of the service.
-
-on rez IDs for communicating information to created object:
-    10008 auto-rez jaunter startup code
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/inventory_exchanger_v3.7.lsl b/huffware/huffotronic_updater_freebie_v5.3/inventory_exchanger_v3.7.lsl
new file mode 100755 (executable)
index 0000000..7a5b6cd
--- /dev/null
@@ -0,0 +1,488 @@
+
+// huffware script: inventory exchanger, by fred huffhines.
+//
+// manages inventory between a root prim and its children.  this script should be placed in
+// all prims that need to exchange contents.  the root prim drives the exchange process based
+// on a registered set of assets that it is told to synchronize in each child.  all the child
+// prims that have this script will ensure they are up to date with respect to those assets.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// inventory exchanger link message API...
+//////////////
+// do not redefine these constants.
+integer INVENTORY_EXCHANGER_HUFFWARE_ID = 10021;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+//string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+// commands available via the library:
+string REGISTER_ASSETS_COMMAND = "#regis#";
+    // makes the root prim's inventory exchanger track a set of items which each participating
+    // child prim should have.  this command is only available to the root prim; child prims
+    // cannot register any assets but instead can get updates on the assets.  the parameter
+    // required is a list of asset definitions, wrapped by the huffware parm separator.  each
+    // asset definition is in turn a two part list wrapped with the asset field separator.
+string ASSET_FIELD_SEPARATOR = "&&";  // separates the type from the name in our list.
+string WILDCARD_INVENTORY_NAME = "ALL";
+    // this keyword can be used to register all of the inventory items available of the
+    // specified type.  this should be passed as the inventory item name in the second half of
+    // an asset definition list.
+string WHACK_INVENTORY_SIGNAL = "DEL*";
+    // ensures that the child prim doesn't maintain *any* of the inventory of the type specified.
+string AVAILABLE_ASSETS_EVENT = "#gotz#";
+    // the root prim publishes this event to list out what items it has available.  the child
+    // prims need to ask for anything that they're currently missing.  the included parameters
+    // are in the same format as the register assets command, but no wildcards will be present;
+    // all asset names will be fully expanded.
+string REQUEST_UPDATES = "#nupd#";
+    // used by the child prim to request an updated version of an asset or assets.  the parameters
+    // should follow the register assets command.
+string FINISHED_UPDATING = "#donq#";
+    // a signal sent from the root prim to the child prim when the root has finished updating
+    // the assets requested.  this lets the child know that it can clean out any outdated versions
+    // of items which got an update.  there are no parameters to this, because the child prim
+    // should have at most one update outstanding at a time.
+//////////////
+
+// constants...
+
+integer TIMER_PERIOD = 600;  // the rate at which the root sends out updates (in seconds).
+
+integer INVEXCH_SCRIPT_PIN = -343781294;  // used to slam scripts into the target prim.
+
+// global variables...
+
+list assets_available;
+    // the set of items that we will provide on demand.  this list has items wrapped with the
+    // asset separator, where the unwrapped entries each provide the type (integer) and the
+    // name of the item.
+
+// gives out items that are asked for in "requested_assets".  these go from the
+// root prim into the kids.
+populate_child_prim(integer link_num, list requested_assets)
+{
+    key asking_child = llGetLinkKey(link_num);  // the kid that needs the update.
+    // look at the assets one by one and pass them over.
+    integer undy;
+    for (undy = 0; undy < llGetListLength(requested_assets); undy++) {
+        // unwrap the next asset definition from the requests.
+        list asset_def = llParseString2List(llList2String(requested_assets, undy),
+            [ASSET_FIELD_SEPARATOR], []);
+        integer type = llList2Integer(asset_def, 0);
+        string name = llList2String(asset_def, 1);
+//log_it("root is giving link " + (string)link_num + " item " + name);
+        // fork over the item itself.
+        if (type != INVENTORY_SCRIPT) {
+            llGiveInventory(asking_child, name);            
+        } else {
+            llRemoteLoadScriptPin(asking_child, name, INVEXCH_SCRIPT_PIN, TRUE, 0);
+        }
+    }
+
+    // we send this event when done updating the kid.     
+    llMessageLinked(link_num, INVENTORY_EXCHANGER_HUFFWARE_ID, FINISHED_UPDATING, NULL_KEY);
+}
+
+// changes the run state of all the scripts besides this one.
+knock_around_other_scripts(integer running_state)
+{
+    // we won't start anything if we're running inside the updater object.
+    if (find_substring(llGetObjectName(), "huffotronic") >= 0) return;
+    
+    integer indy;
+    string self_script = llGetScriptName();
+    // we set all other scripts to the running state requested.
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
+        if (curr_script != self_script) {
+            // this one seems ripe for being set to the state requested.
+            llSetScriptState(curr_script, running_state);
+        }
+    }
+}
+
+// kicks forward the periodic activities of the exchange process.
+handle_timer()
+{
+    if (llGetLinkNumber() != 1) {
+        // child prim activities only.
+//        knock_around_other_scripts(TRUE);
+        return;
+    } else {
+        // the rest are root prim timer activities.
+        if (llGetListLength(assets_available) == 0) return;  // nothing to do here.
+        // the root needs to send out link messages telling kids what good stuff its got.
+        llMessageLinked(LINK_ALL_CHILDREN, INVENTORY_EXCHANGER_HUFFWARE_ID,
+            AVAILABLE_ASSETS_EVENT, wrap_parameters(assets_available));
+    }
+
+}
+
+// given a packed up list of items, this breaks out each asset definition and
+// begins using the set as our full list of available items.
+consume_asset_registration(string packed_assets)
+{
+    assets_available = llParseString2List(packed_assets, [HUFFWARE_PARM_SEPARATOR], []);
+//hmmm: future enhancement might be to allow multiple clients of the root exchanger.
+//      currently we only support one script inside the root prim listing assets for inv exch.
+//      that's shown just above where we're just replacing the entire registered assets list.
+
+    integer indy;
+    for (indy = 0; indy < llGetListLength(assets_available); indy++) {
+        list asset_def = llParseString2List(llList2String(assets_available, indy),
+            [ASSET_FIELD_SEPARATOR], []);
+        integer type = llList2Integer(asset_def, 0);
+        string name = llList2String(asset_def, 1);
+        if (name == WILDCARD_INVENTORY_NAME) {
+            // argh, we need to patch up the list for a wildcard option.
+            // first, whack the item with the wildcard in it.
+            assets_available = llDeleteSubList(assets_available, indy, indy);
+            // now revert the list index for the missing item.
+            indy--;
+            // and finally add all the items of that type.  if one of them is named
+            // after the wildcard character, well, we disallow that craziness.
+            integer inv_pos;
+            for (inv_pos = 0; inv_pos < llGetInventoryNumber(type); inv_pos++) {
+                string inv_name = llGetInventoryName(type, inv_pos);
+                if (inv_name != WILDCARD_INVENTORY_NAME) {
+//log_it("added wild: " + inv_name);
+                    assets_available += [ llDumpList2String([type, inv_name], ASSET_FIELD_SEPARATOR) ];
+                }
+            }
+            
+        }
+    }
+    
+    // make sure we get this new set out to the interested parties.
+    handle_timer();    
+}
+
+// note that this new, lower memory version, depends on the inventory functions returning
+// items in alphabetical order.
+scrub_items_by_type(string this_guy, integer inventory_type)
+{
+    list removal_list;
+    integer outer;
+    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
+        string curr = llGetInventoryName(inventory_type, outer);
+        list split = compute_basename_and_version(curr);
+        // make sure there was a comparable version number in this name.
+        if ( (curr != this_guy) && llGetListLength(split)) {
+            string curr_base = llList2String(split, 0);
+            float curr_ver = (float)llList2String(split, 1);
+//log_it("outer: " + curr_base + " / " + (string)curr_ver);
+            integer inner;
+            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
+                string next_guy = llGetInventoryName(inventory_type, inner);
+                list comp_split = compute_basename_and_version(next_guy);
+                if (llGetListLength(comp_split)) {
+                    string comp_base = llList2String(comp_split, 0);
+                    float comp_ver = (float)llList2String(comp_split, 1);
+                    // okay, now we can actually compare.
+                    if (curr_base != comp_base) {
+                        // break out of inner loop.  we are past where the names can matter.
+                        inner = 2 * llGetInventoryNumber(inventory_type);
+                    } else {
+//log_it("inner: " + comp_base + " / " + (string)comp_ver);
+                        if (curr_ver <= comp_ver) {
+                            // the script at inner index is comparable or better than
+                            // the script at the outer index.
+                            removal_list += curr;
+                        } else {
+                            // this inner script must be inferior to the outer one,
+                            // somehow, which defies our expectation of alphabetical ordering.
+                            removal_list += next_guy;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // now actually do the deletions.
+    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
+        string to_whack = llList2String(removal_list, outer);
+log_it("removing older asset: " + to_whack);
+        llRemoveInventory(to_whack);
+    }
+}
+
+// ensures that only the latest version of any script or object is kept in our inventory.
+// has been called destroy_older_versions in other scripts.
+clean_outdated_items()
+{
+    scrub_items_by_type(llGetScriptName(), INVENTORY_ALL);
+    // after cleaning up, make sure everything's running.
+    knock_around_other_scripts(TRUE);    
+}
+
+// locates the index of a specified type of inventory item with a particular name,
+// or returns a negative number.
+integer find_inventory(integer type, string name)
+{
+    integer indy;
+    for (indy = 0; indy < llGetInventoryNumber(type); indy++) {
+        if (name == llGetInventoryName(type, indy)) return indy;
+    }
+    return -1;
+}
+
+// called on child prims to make sure they have everything the root does.
+examine_inventory_freshness(string packed_assets)
+{
+    list missing_goods;  // fill this with the things we don't have in this prim.
+    list provisions = llParseString2List(packed_assets, [HUFFWARE_PARM_SEPARATOR], []);
+    integer indy;
+    // scan through all the items that are available and make sure we have each of them.
+    for (indy = 0; indy < llGetListLength(provisions); indy++) {
+        string prov = llList2String(provisions, indy);
+        list fields = llParseString2List(prov, [ASSET_FIELD_SEPARATOR], []);
+//log_it("checking: " + llList2String(fields, 1) + " type=" + (string)llList2Integer(fields, 0));
+        // look for the type and name specified.
+        integer type = llList2Integer(fields, 0);
+        string name = llList2String(fields, 1);
+        if (name == WHACK_INVENTORY_SIGNAL) {
+            // we see our special signifier, so remove all items of the type specified.
+            // yes, this is dangerous.
+            integer delo;
+            for (delo = llGetInventoryNumber(type) - 1; delo >= 0; delo--) {
+                llRemoveInventory(llGetInventoryName(type, delo));
+            }
+        } else {
+            integer found = find_inventory(type, name);
+            if (found < 0) {
+//log_it("found " + llList2String(fields, 1) + " was missing!");
+                // well, we are out of this one.  tell the root we want it.
+                missing_goods += [ prov ];
+            }
+        }
+    }
+    if (llGetListLength(missing_goods) > 0) {
+        // well we found some things that we're supposed to have, but do not.  we will
+        // get the root prim to fix us up.
+        llMessageLinked(LINK_ROOT, INVENTORY_EXCHANGER_HUFFWARE_ID,
+            REQUEST_UPDATES, wrap_parameters(missing_goods));
+    }
+}
+
+//hmmm: this is not such a good model?  why do the root and
+//  the child both need to be running this check on a timer?
+
+// processes inventory exchange commands in the root prim.  this is where assets must
+// be present so they can be distributed to the child prims.
+process_root_msg(integer link_num, integer service, string cmd, key parms)
+{
+    if (service != INVENTORY_EXCHANGER_HUFFWARE_ID) return;  // not for us.
+//string name="root";
+//if (llGetLinkNumber() != 1) name="child";
+//log_it(name + " got request " + cmd);
+    if (link_num == 1) {
+        // this request is also from the root prim, where this script lives currently.
+        if (cmd == REGISTER_ASSETS_COMMAND) {
+            // root prim accepts a list of assets to provide to the kids.
+            consume_asset_registration(parms);
+        }
+    } else {
+        // a request is coming from a child prim.
+        if (cmd == REQUEST_UPDATES) {
+            // the root prim responds to update requests by handing out presents.
+            populate_child_prim(link_num, llParseString2List(parms, [HUFFWARE_PARM_SEPARATOR], []));
+        }
+    }
+}
+
+// implements the child API, mainly to track missing assets and clean out outdated items.
+process_child_msg(integer link_num, integer service, string cmd, key parms)
+{
+    if (service != INVENTORY_EXCHANGER_HUFFWARE_ID) return;  // not for us.
+    if (link_num != 1) return;  // we don't listen to any chatter from other children.
+    if (cmd == AVAILABLE_ASSETS_EVENT) {
+        examine_inventory_freshness(parms);
+    } else if (cmd == FINISHED_UPDATING) {
+        clean_outdated_items();
+    }
+}
+
+// main processing function for the link messge API.
+handle_link_message(integer link_num, integer service, string cmd, key parms)
+{
+    if (llGetLinkNumber() == 1) process_root_msg(link_num, service, cmd, parms);
+    else process_child_msg(link_num, service, cmd, parms);
+}
+
+//////////////
+// beginning of hufflets...
+//////////////
+
+// diagnostic hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+
+// joins a list of sub-items using the item sentinel for the library.
+//string wrap_item_list(list to_wrap)
+//{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+// end hufflets
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+///log_it("\n\n\n\n\n\n\n\n\n** starting now............................");
+        // register child prims for script replacement.
+        if (llGetLinkNumber() != 1) llSetRemoteScriptAccessPin(INVEXCH_SCRIPT_PIN);
+        //new idea; only allow timers to run in root prim.
+        if (llGetLinkNumber() == 1) llSetTimerEvent(TIMER_PERIOD);
+        knock_around_other_scripts(TRUE);
+        // first run happens right at startup.
+        if (llGetLinkNumber() == 1) handle_timer();
+    }
+
+    timer() {
+        llSetTimerEvent(0);  // stop timer.
+        handle_timer();
+        llSetTimerEvent(TIMER_PERIOD);  // start timer.
+    }
+
+    link_message(integer link_num, integer service, string cmd, key parms) {
+        handle_link_message(link_num, service, cmd, parms);
+    }
+}
+
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/inventory_exchanger_v3.7.txt b/huffware/huffotronic_updater_freebie_v5.3/inventory_exchanger_v3.7.txt
deleted file mode 100755 (executable)
index 7a5b6cd..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-
-// huffware script: inventory exchanger, by fred huffhines.
-//
-// manages inventory between a root prim and its children.  this script should be placed in
-// all prims that need to exchange contents.  the root prim drives the exchange process based
-// on a registered set of assets that it is told to synchronize in each child.  all the child
-// prims that have this script will ensure they are up to date with respect to those assets.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// inventory exchanger link message API...
-//////////////
-// do not redefine these constants.
-integer INVENTORY_EXCHANGER_HUFFWARE_ID = 10021;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-//string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-// commands available via the library:
-string REGISTER_ASSETS_COMMAND = "#regis#";
-    // makes the root prim's inventory exchanger track a set of items which each participating
-    // child prim should have.  this command is only available to the root prim; child prims
-    // cannot register any assets but instead can get updates on the assets.  the parameter
-    // required is a list of asset definitions, wrapped by the huffware parm separator.  each
-    // asset definition is in turn a two part list wrapped with the asset field separator.
-string ASSET_FIELD_SEPARATOR = "&&";  // separates the type from the name in our list.
-string WILDCARD_INVENTORY_NAME = "ALL";
-    // this keyword can be used to register all of the inventory items available of the
-    // specified type.  this should be passed as the inventory item name in the second half of
-    // an asset definition list.
-string WHACK_INVENTORY_SIGNAL = "DEL*";
-    // ensures that the child prim doesn't maintain *any* of the inventory of the type specified.
-string AVAILABLE_ASSETS_EVENT = "#gotz#";
-    // the root prim publishes this event to list out what items it has available.  the child
-    // prims need to ask for anything that they're currently missing.  the included parameters
-    // are in the same format as the register assets command, but no wildcards will be present;
-    // all asset names will be fully expanded.
-string REQUEST_UPDATES = "#nupd#";
-    // used by the child prim to request an updated version of an asset or assets.  the parameters
-    // should follow the register assets command.
-string FINISHED_UPDATING = "#donq#";
-    // a signal sent from the root prim to the child prim when the root has finished updating
-    // the assets requested.  this lets the child know that it can clean out any outdated versions
-    // of items which got an update.  there are no parameters to this, because the child prim
-    // should have at most one update outstanding at a time.
-//////////////
-
-// constants...
-
-integer TIMER_PERIOD = 600;  // the rate at which the root sends out updates (in seconds).
-
-integer INVEXCH_SCRIPT_PIN = -343781294;  // used to slam scripts into the target prim.
-
-// global variables...
-
-list assets_available;
-    // the set of items that we will provide on demand.  this list has items wrapped with the
-    // asset separator, where the unwrapped entries each provide the type (integer) and the
-    // name of the item.
-
-// gives out items that are asked for in "requested_assets".  these go from the
-// root prim into the kids.
-populate_child_prim(integer link_num, list requested_assets)
-{
-    key asking_child = llGetLinkKey(link_num);  // the kid that needs the update.
-    // look at the assets one by one and pass them over.
-    integer undy;
-    for (undy = 0; undy < llGetListLength(requested_assets); undy++) {
-        // unwrap the next asset definition from the requests.
-        list asset_def = llParseString2List(llList2String(requested_assets, undy),
-            [ASSET_FIELD_SEPARATOR], []);
-        integer type = llList2Integer(asset_def, 0);
-        string name = llList2String(asset_def, 1);
-//log_it("root is giving link " + (string)link_num + " item " + name);
-        // fork over the item itself.
-        if (type != INVENTORY_SCRIPT) {
-            llGiveInventory(asking_child, name);            
-        } else {
-            llRemoteLoadScriptPin(asking_child, name, INVEXCH_SCRIPT_PIN, TRUE, 0);
-        }
-    }
-
-    // we send this event when done updating the kid.     
-    llMessageLinked(link_num, INVENTORY_EXCHANGER_HUFFWARE_ID, FINISHED_UPDATING, NULL_KEY);
-}
-
-// changes the run state of all the scripts besides this one.
-knock_around_other_scripts(integer running_state)
-{
-    // we won't start anything if we're running inside the updater object.
-    if (find_substring(llGetObjectName(), "huffotronic") >= 0) return;
-    
-    integer indy;
-    string self_script = llGetScriptName();
-    // we set all other scripts to the running state requested.
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_SCRIPT); indy++) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, indy);
-        if (curr_script != self_script) {
-            // this one seems ripe for being set to the state requested.
-            llSetScriptState(curr_script, running_state);
-        }
-    }
-}
-
-// kicks forward the periodic activities of the exchange process.
-handle_timer()
-{
-    if (llGetLinkNumber() != 1) {
-        // child prim activities only.
-//        knock_around_other_scripts(TRUE);
-        return;
-    } else {
-        // the rest are root prim timer activities.
-        if (llGetListLength(assets_available) == 0) return;  // nothing to do here.
-        // the root needs to send out link messages telling kids what good stuff its got.
-        llMessageLinked(LINK_ALL_CHILDREN, INVENTORY_EXCHANGER_HUFFWARE_ID,
-            AVAILABLE_ASSETS_EVENT, wrap_parameters(assets_available));
-    }
-
-}
-
-// given a packed up list of items, this breaks out each asset definition and
-// begins using the set as our full list of available items.
-consume_asset_registration(string packed_assets)
-{
-    assets_available = llParseString2List(packed_assets, [HUFFWARE_PARM_SEPARATOR], []);
-//hmmm: future enhancement might be to allow multiple clients of the root exchanger.
-//      currently we only support one script inside the root prim listing assets for inv exch.
-//      that's shown just above where we're just replacing the entire registered assets list.
-
-    integer indy;
-    for (indy = 0; indy < llGetListLength(assets_available); indy++) {
-        list asset_def = llParseString2List(llList2String(assets_available, indy),
-            [ASSET_FIELD_SEPARATOR], []);
-        integer type = llList2Integer(asset_def, 0);
-        string name = llList2String(asset_def, 1);
-        if (name == WILDCARD_INVENTORY_NAME) {
-            // argh, we need to patch up the list for a wildcard option.
-            // first, whack the item with the wildcard in it.
-            assets_available = llDeleteSubList(assets_available, indy, indy);
-            // now revert the list index for the missing item.
-            indy--;
-            // and finally add all the items of that type.  if one of them is named
-            // after the wildcard character, well, we disallow that craziness.
-            integer inv_pos;
-            for (inv_pos = 0; inv_pos < llGetInventoryNumber(type); inv_pos++) {
-                string inv_name = llGetInventoryName(type, inv_pos);
-                if (inv_name != WILDCARD_INVENTORY_NAME) {
-//log_it("added wild: " + inv_name);
-                    assets_available += [ llDumpList2String([type, inv_name], ASSET_FIELD_SEPARATOR) ];
-                }
-            }
-            
-        }
-    }
-    
-    // make sure we get this new set out to the interested parties.
-    handle_timer();    
-}
-
-// note that this new, lower memory version, depends on the inventory functions returning
-// items in alphabetical order.
-scrub_items_by_type(string this_guy, integer inventory_type)
-{
-    list removal_list;
-    integer outer;
-    for (outer = 0; outer < llGetInventoryNumber(inventory_type); outer++) {
-        string curr = llGetInventoryName(inventory_type, outer);
-        list split = compute_basename_and_version(curr);
-        // make sure there was a comparable version number in this name.
-        if ( (curr != this_guy) && llGetListLength(split)) {
-            string curr_base = llList2String(split, 0);
-            float curr_ver = (float)llList2String(split, 1);
-//log_it("outer: " + curr_base + " / " + (string)curr_ver);
-            integer inner;
-            for (inner = outer + 1; inner < llGetInventoryNumber(inventory_type); inner++) {
-                string next_guy = llGetInventoryName(inventory_type, inner);
-                list comp_split = compute_basename_and_version(next_guy);
-                if (llGetListLength(comp_split)) {
-                    string comp_base = llList2String(comp_split, 0);
-                    float comp_ver = (float)llList2String(comp_split, 1);
-                    // okay, now we can actually compare.
-                    if (curr_base != comp_base) {
-                        // break out of inner loop.  we are past where the names can matter.
-                        inner = 2 * llGetInventoryNumber(inventory_type);
-                    } else {
-//log_it("inner: " + comp_base + " / " + (string)comp_ver);
-                        if (curr_ver <= comp_ver) {
-                            // the script at inner index is comparable or better than
-                            // the script at the outer index.
-                            removal_list += curr;
-                        } else {
-                            // this inner script must be inferior to the outer one,
-                            // somehow, which defies our expectation of alphabetical ordering.
-                            removal_list += next_guy;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // now actually do the deletions.
-    for (outer = 0; outer < llGetListLength(removal_list); outer++) {
-        string to_whack = llList2String(removal_list, outer);
-log_it("removing older asset: " + to_whack);
-        llRemoveInventory(to_whack);
-    }
-}
-
-// ensures that only the latest version of any script or object is kept in our inventory.
-// has been called destroy_older_versions in other scripts.
-clean_outdated_items()
-{
-    scrub_items_by_type(llGetScriptName(), INVENTORY_ALL);
-    // after cleaning up, make sure everything's running.
-    knock_around_other_scripts(TRUE);    
-}
-
-// locates the index of a specified type of inventory item with a particular name,
-// or returns a negative number.
-integer find_inventory(integer type, string name)
-{
-    integer indy;
-    for (indy = 0; indy < llGetInventoryNumber(type); indy++) {
-        if (name == llGetInventoryName(type, indy)) return indy;
-    }
-    return -1;
-}
-
-// called on child prims to make sure they have everything the root does.
-examine_inventory_freshness(string packed_assets)
-{
-    list missing_goods;  // fill this with the things we don't have in this prim.
-    list provisions = llParseString2List(packed_assets, [HUFFWARE_PARM_SEPARATOR], []);
-    integer indy;
-    // scan through all the items that are available and make sure we have each of them.
-    for (indy = 0; indy < llGetListLength(provisions); indy++) {
-        string prov = llList2String(provisions, indy);
-        list fields = llParseString2List(prov, [ASSET_FIELD_SEPARATOR], []);
-//log_it("checking: " + llList2String(fields, 1) + " type=" + (string)llList2Integer(fields, 0));
-        // look for the type and name specified.
-        integer type = llList2Integer(fields, 0);
-        string name = llList2String(fields, 1);
-        if (name == WHACK_INVENTORY_SIGNAL) {
-            // we see our special signifier, so remove all items of the type specified.
-            // yes, this is dangerous.
-            integer delo;
-            for (delo = llGetInventoryNumber(type) - 1; delo >= 0; delo--) {
-                llRemoveInventory(llGetInventoryName(type, delo));
-            }
-        } else {
-            integer found = find_inventory(type, name);
-            if (found < 0) {
-//log_it("found " + llList2String(fields, 1) + " was missing!");
-                // well, we are out of this one.  tell the root we want it.
-                missing_goods += [ prov ];
-            }
-        }
-    }
-    if (llGetListLength(missing_goods) > 0) {
-        // well we found some things that we're supposed to have, but do not.  we will
-        // get the root prim to fix us up.
-        llMessageLinked(LINK_ROOT, INVENTORY_EXCHANGER_HUFFWARE_ID,
-            REQUEST_UPDATES, wrap_parameters(missing_goods));
-    }
-}
-
-//hmmm: this is not such a good model?  why do the root and
-//  the child both need to be running this check on a timer?
-
-// processes inventory exchange commands in the root prim.  this is where assets must
-// be present so they can be distributed to the child prims.
-process_root_msg(integer link_num, integer service, string cmd, key parms)
-{
-    if (service != INVENTORY_EXCHANGER_HUFFWARE_ID) return;  // not for us.
-//string name="root";
-//if (llGetLinkNumber() != 1) name="child";
-//log_it(name + " got request " + cmd);
-    if (link_num == 1) {
-        // this request is also from the root prim, where this script lives currently.
-        if (cmd == REGISTER_ASSETS_COMMAND) {
-            // root prim accepts a list of assets to provide to the kids.
-            consume_asset_registration(parms);
-        }
-    } else {
-        // a request is coming from a child prim.
-        if (cmd == REQUEST_UPDATES) {
-            // the root prim responds to update requests by handing out presents.
-            populate_child_prim(link_num, llParseString2List(parms, [HUFFWARE_PARM_SEPARATOR], []));
-        }
-    }
-}
-
-// implements the child API, mainly to track missing assets and clean out outdated items.
-process_child_msg(integer link_num, integer service, string cmd, key parms)
-{
-    if (service != INVENTORY_EXCHANGER_HUFFWARE_ID) return;  // not for us.
-    if (link_num != 1) return;  // we don't listen to any chatter from other children.
-    if (cmd == AVAILABLE_ASSETS_EVENT) {
-        examine_inventory_freshness(parms);
-    } else if (cmd == FINISHED_UPDATING) {
-        clean_outdated_items();
-    }
-}
-
-// main processing function for the link messge API.
-handle_link_message(integer link_num, integer service, string cmd, key parms)
-{
-    if (llGetLinkNumber() == 1) process_root_msg(link_num, service, cmd, parms);
-    else process_child_msg(link_num, service, cmd, parms);
-}
-
-//////////////
-// beginning of hufflets...
-//////////////
-
-// diagnostic hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-
-// joins a list of sub-items using the item sentinel for the library.
-//string wrap_item_list(list to_wrap)
-//{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-// end hufflets
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-///log_it("\n\n\n\n\n\n\n\n\n** starting now............................");
-        // register child prims for script replacement.
-        if (llGetLinkNumber() != 1) llSetRemoteScriptAccessPin(INVEXCH_SCRIPT_PIN);
-        //new idea; only allow timers to run in root prim.
-        if (llGetLinkNumber() == 1) llSetTimerEvent(TIMER_PERIOD);
-        knock_around_other_scripts(TRUE);
-        // first run happens right at startup.
-        if (llGetLinkNumber() == 1) handle_timer();
-    }
-
-    timer() {
-        llSetTimerEvent(0);  // stop timer.
-        handle_timer();
-        llSetTimerEvent(TIMER_PERIOD);  // start timer.
-    }
-
-    link_message(integer link_num, integer service, string cmd, key parms) {
-        handle_link_message(link_num, service, cmd, parms);
-    }
-}
-
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/license__free_in_osgrid_only_v1.8.lsl b/huffware/huffotronic_updater_freebie_v5.3/license__free_in_osgrid_only_v1.8.lsl
new file mode 100755 (executable)
index 0000000..b28cd30
--- /dev/null
@@ -0,0 +1,26 @@
+--license version: april 24 2011--
+author: fred huffhines (osgrid and second life avatar)
+source: eepaw shop (see below)
+all content by fred huffhines is licensed by GPL [ http://www.gnu.org/licenses/gpl.html ] within the full metaverse (osgrid, opensims, second life, etc).
+note that any included content created by others may be licensed differently; all appropriate original copyright notices have been retained.
+price in osgrid: *free*
+    ** note: if you paid for this in osgrid, someone ripped you off.  please let fred huffhines (in osgrid) know about this.
+price in second life: *non-free*
+    ** note: the only avatar licensed to sell materials within this product is fred huffhines in second life.
+          if you bought this from someone else, please let fred huffhines know.
+price in other grids: *unspecified*
+    ** we're still developing a relationship with other grids, but any opensim-based-server user can use any of this content on their personal standalone/hypergrid sims for free.  we ask that you please do not share any of this content on commercial grids yet.
+    ** please let us know if you're interested in expanding our licensing to your commercial grid.
+
+* our store is called Eclectic Electric Patterns and Widgets (eepaw).  we started out in Second life, but have since branched out into opensim based simulators.  we have two locations for the store now, one in osgrid that is all ++freebies++, and another store in second life that is a mix of commercial objects and freebies (because the linden labs dingbats insist on charging exorbitant rates to rent space on their servers).
+
+* in osgrid: our brand new freebie store (as of march 2011) is in wright plaza at <228, 22, 21>
+    [ or http://slurl.com/secondlife/Wright%20Plaza/228/22/21 ].
+this will be our base of operations from now on, or until there's no power left in the global electrical grid.
+a lot of our new stuff will be available here first, and for free to osgrid avatars.
+please don't upload our stuff into second life, because that store (see below) kind of needs to pay for itself.  render unto caesar and all that.  so, thanks.
+
+* in second life: the eepaw shop is located way out in the "smoky" region of the atoll (heterocera).  Feel free to mosey over and check our other strange devices out, many others of which are also totally free...
+    http://slurl.com/secondlife/Smoky/14/84/405
+
+* we are personally very fond of each of you.  --fred huffhines.
diff --git a/huffware/huffotronic_updater_freebie_v5.3/license__free_in_osgrid_only_v1.8.txt b/huffware/huffotronic_updater_freebie_v5.3/license__free_in_osgrid_only_v1.8.txt
deleted file mode 100755 (executable)
index b28cd30..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
---license version: april 24 2011--
-author: fred huffhines (osgrid and second life avatar)
-source: eepaw shop (see below)
-all content by fred huffhines is licensed by GPL [ http://www.gnu.org/licenses/gpl.html ] within the full metaverse (osgrid, opensims, second life, etc).
-note that any included content created by others may be licensed differently; all appropriate original copyright notices have been retained.
-price in osgrid: *free*
-    ** note: if you paid for this in osgrid, someone ripped you off.  please let fred huffhines (in osgrid) know about this.
-price in second life: *non-free*
-    ** note: the only avatar licensed to sell materials within this product is fred huffhines in second life.
-          if you bought this from someone else, please let fred huffhines know.
-price in other grids: *unspecified*
-    ** we're still developing a relationship with other grids, but any opensim-based-server user can use any of this content on their personal standalone/hypergrid sims for free.  we ask that you please do not share any of this content on commercial grids yet.
-    ** please let us know if you're interested in expanding our licensing to your commercial grid.
-
-* our store is called Eclectic Electric Patterns and Widgets (eepaw).  we started out in Second life, but have since branched out into opensim based simulators.  we have two locations for the store now, one in osgrid that is all ++freebies++, and another store in second life that is a mix of commercial objects and freebies (because the linden labs dingbats insist on charging exorbitant rates to rent space on their servers).
-
-* in osgrid: our brand new freebie store (as of march 2011) is in wright plaza at <228, 22, 21>
-    [ or http://slurl.com/secondlife/Wright%20Plaza/228/22/21 ].
-this will be our base of operations from now on, or until there's no power left in the global electrical grid.
-a lot of our new stuff will be available here first, and for free to osgrid avatars.
-please don't upload our stuff into second life, because that store (see below) kind of needs to pay for itself.  render unto caesar and all that.  so, thanks.
-
-* in second life: the eepaw shop is located way out in the "smoky" region of the atoll (heterocera).  Feel free to mosey over and check our other strange devices out, many others of which are also totally free...
-    http://slurl.com/secondlife/Smoky/14/84/405
-
-* we are personally very fond of each of you.  --fred huffhines.
diff --git a/huffware/huffotronic_updater_freebie_v5.3/menu_list_manager_v12.4.lsl b/huffware/huffotronic_updater_freebie_v5.3/menu_list_manager_v12.4.lsl
new file mode 100755 (executable)
index 0000000..22ddbe4
--- /dev/null
@@ -0,0 +1,533 @@
+
+// huffware script: menu list manager, by fred huffhines.
+//
+// deals with popping up menus when desired.  does not do any configuration
+// reading; that all must be fed to the script via link messages.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants...
+
+string GIFTING_MENU_NAME = "#gifting#";
+    // the menu name that we support internally for giving gifts.
+
+// global variables...
+
+// these are the definition of the menuing system,
+// and are valid once we have heard our config.
+
+// unique identifiers of menu names.
+list menu_names;
+// a list of titles for the menus.
+list menu_titles;
+// the menu choices are strings containing encoded lists of button text labels.
+list menu_button_lists;
+
+// store current activated menu info...
+string _private_global_av_name;
+string _private_global_av_key;
+
+// menu list manager link message API.
+//////////////
+// do not redefine these constants.
+integer MENU_LIST_MANAGER_HUFFWARE_ID = 10033;
+    // the unique id within the huffware system for this sensor plugin script.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string MENU_LIST_MGR_RESET = "#ml-reset#";
+    // throws out any current menus and gets ready to load a new set.
+string MENU_LIST_MGR_ADD_MENU = "#ml-addmenu#";
+    // puts a new menu into our list.  this requires 3 parameters: menu name,
+    // menu title, menu button list.
+string MENU_LIST_MGR_SHOW_MENU = "#ml-shomenu#";
+    // a request that a particular menu be shown.  the first parameter is the menu index.
+    // the second parameter is the avatar name.  the third parameter is the avatar key.
+string MENU_LIST_MGR_GIVE_ITEM = "#ml-give#";
+    // brings up a gift giving menu.  parms are avatar name and avatar key.
+string MENU_LIST_MGR_MODIFY_MENU = "#ml-modmenu#";
+string MENU_LIST_KEEP_WORD = "KEEP";
+    // replaces a menu already in the list.  this requires 4 parameters: menu index, menu name,
+    // menu title, menu button list.  if a parameter is the MENU_LIST_KEEP_WORD, then that field
+    // is not changed.
+string MENU_LIST_MGR_CHOICE_MADE_ALERT = "#ml-event-picked";
+    // alerts the driver for this script that the owner has picked a choice.  the
+    // parameters include: the text of the choice, the name of the menu, the avatar name,
+    // the avatar key.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// requires HUD sensor plugin v21.4 or better.
+//////////////
+// do not redefine these constants.
+integer SENSOR_PLUGIN_HUFFWARE_ID = 10014;
+    // the unique id within the huffware system for this sensor plugin script.
+string GIVE_ALL_AVATARS = "#santa#";
+    // if this is received, the sensor plugin attempts to hand out an object passed as
+    // the first parameter to every avatar it knows about.
+//////////////
+
+// requires menutini v3.9 or better...
+//////////////
+// do not redefine these constants.
+integer MENUTINI_HUFFWARE_ID = 10009;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+// commands available via menutini:
+string SHOW_MENU_COMMAND = "#menu#";
+    // the command that tells menutini to show a menu defined by parameters
+    // that are passed along.  these must be: the menu name, the menu's title
+    // (which is really the info to show as content in the main box of the menu),
+    // the wrapped list of commands to show as menu buttons, the menu system
+    // channel's for listening, and the key to listen to.
+//
+//////////////
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+//
+//////////////
+
+// replaces occurences of $owner and $avatar with the owner's name and the
+// targeted avatars name.  _first and _last added to the name cause the first
+// or last name to be used instead.
+string senso_substitute_vars(string to_substitute, string avatars_name)
+{
+    string owners_name = llKey2Name(llGetOwner());
+    return substitute_variable_list(to_substitute,
+        [ "avatar_first", "avatar_last", "avatar",
+            "owner_first", "owner_last", "owner" ],
+        [ first_name(avatars_name), last_name(avatars_name), avatars_name,
+           first_name(owners_name), last_name(owners_name), owners_name ]);
+}
+
+integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
+
+simply_display_menu(string menu_name, string title, list buttons,
+    string av_name, string av_key)
+{
+    // we only manage one global now for this stuff...
+    _private_global_av_name = av_name;
+    _private_global_av_key = av_key;
+
+    integer menu_channel = random_channel();
+    key listen_to = llGetOwner();
+//log_it("passing in key to use: " + (string)listen_to);
+    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
+        menu_name + HUFFWARE_PARM_SEPARATOR
+        + title + HUFFWARE_PARM_SEPARATOR
+        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
+        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
+        + (string)listen_to);
+}
+
+replace_vars_and_display_menu(integer menu_index, string av_name, string av_key)
+{
+    // patch the avatar names and owner names before displaying.
+    string title = senso_substitute_vars(llList2String(menu_titles, menu_index), av_name);
+    string button_text = llList2String(menu_button_lists, menu_index);
+
+    simply_display_menu(llList2String(menu_names, menu_index), title,
+        llParseString2List(button_text, [HUFFWARE_ITEM_SEPARATOR], []),
+        av_name, av_key);
+}
+
+// shows a menu by index.
+show_menu(integer index, string av_name, string av_key)
+{
+    replace_vars_and_display_menu(index, av_name, av_key);
+//log_it("sent the menu request...  memory left=" + (string)llGetFreeMemory());
+}
+
+// handles the response message when the user chooses a button.
+react_to_menu(string menu_name, string av_name, string av_key, string which_choice)
+{
+//log_it("you clicked " + which_choice + " item for av " + av_name);
+    handle_chosen_menu_item(menu_name, av_name, av_key, which_choice);
+}
+
+// the gift giving menu.  we show the menu after looking through the
+// inventory.  if the owner picks an item, we'll deal with that response.
+show_gift_menu(string av_name, string av_key)
+{
+    string menu_name = "gift";
+    string menu_title = "Pick a gift for " + av_name + "...";
+    list menu_button_list = [];
+    integer indy;
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_OBJECT); indy++) {
+        menu_button_list += llGetInventoryName(INVENTORY_OBJECT, indy);
+    }
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_TEXTURE); indy++) {
+        string item_name = llGetInventoryName(INVENTORY_TEXTURE, indy);
+        if (!is_prefix(item_name, "ean hud keys"))
+            menu_button_list += item_name;
+    }
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_LANDMARK); indy++) {
+        menu_button_list += llGetInventoryName(INVENTORY_LANDMARK, indy);
+    }
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_NOTECARD); indy++) {
+        string item_name = llGetInventoryName(INVENTORY_NOTECARD, indy);
+        if ( (find_substring(item_name, "help") < 0)
+            && (find_substring(item_name, "Help") < 0)
+            && (find_substring(item_name, "config") < 0) )
+            menu_button_list += item_name;
+    }
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_CLOTHING); indy++) {
+        menu_button_list += llGetInventoryName(INVENTORY_CLOTHING, indy);
+    }
+    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_GESTURE); indy++) {
+        menu_button_list += llGetInventoryName(INVENTORY_GESTURE, indy);
+    }
+    
+    if (llGetListLength(menu_button_list) == 0) {
+        llOwnerSay("There are no objects loaded in the hud currently.  I can make no gifts.");
+    }
+    simply_display_menu(GIFTING_MENU_NAME, menu_title, menu_button_list,
+        av_name, av_key);
+}
+
+// handles a request for this library itself.
+process_hud_menu_mgr_request(integer sender, integer num, string msg, key id)
+{
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    if (msg == MENU_LIST_MGR_RESET) {
+        llResetScript();
+    } else if (msg == MENU_LIST_MGR_ADD_MENU) {
+        if (llGetListLength(parms) < 3) {
+            log_it("too few parms to add menu.");
+            return;
+        }
+//hmmm: sloppy list processing!
+        menu_names += [ llList2String(parms, 0) ];
+        menu_titles += [ llList2String(parms, 1) ];
+        menu_button_lists += [ llList2String(parms, 2) ];
+    } else if (msg == MENU_LIST_MGR_GIVE_ITEM) {
+        // give over a gift.
+        string av_name = llList2String(parms, 0);
+        string av_key = llList2String(parms, 1);
+        show_gift_menu(av_name, av_key);
+    } else if (msg == MENU_LIST_MGR_SHOW_MENU) {
+        if (llGetListLength(parms) < 3) {
+            log_it("too few parms to show menu.");
+            return;
+        }
+//log_it("key comes as " + llList2String(parms, 2));
+        show_menu((integer)llList2String(parms, 0), llList2String(parms, 1),
+            (key)llList2String(parms, 2));
+//log_it("show menu...  memory left=" + (string)llGetFreeMemory());
+    } else if (msg == MENU_LIST_MGR_MODIFY_MENU) {
+        if (llGetListLength(parms) < 4) {
+            log_it("too few parms to replace menu.");
+            return;
+        }
+        integer indo = (integer)llList2String(parms, 0);
+//log_it("modif menu request, indo is " + (string)indo);
+        if (indo >= llGetListLength(menu_names)) {
+//log_it("index too large in replace menu");
+            return;
+        }
+//log_it("replacing entry " + (string)indo + " with " + llList2String(parms, 1) + ", " + llList2String(parms, 2) + ", " + llList2String(parms, 3));
+        if (llList2String(parms, 1) != MENU_LIST_KEEP_WORD)
+            menu_names = replace_entry(menu_names, indo, [ llList2String(parms, 1) ]);
+        if (llList2String(parms, 2) != MENU_LIST_KEEP_WORD)
+            menu_titles = replace_entry(menu_titles, indo, [ llList2String(parms, 2) ]);
+        if (llList2String(parms, 3) != MENU_LIST_KEEP_WORD)
+            menu_button_lists = replace_entry(menu_button_lists, indo, [ llList2String(parms, 3) ]);
+//log_it("new menu button:" + llList2String(parms, 3));
+    }
+}
+
+// processes a message from a link.  some of this must be handled
+// by the driver script that handles our configuration.
+handle_link_message(integer sender, integer num, string msg, key id)
+{
+    if (num == MENU_LIST_MANAGER_HUFFWARE_ID) {
+        process_hud_menu_mgr_request(sender, num, msg, id);
+    }
+    
+    if ( (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE)
+        || (msg != SHOW_MENU_COMMAND) ) return;  // not for us.
+
+//log_it("menu reply: sndr=" + (string)sender + " num=" + (string)num + " msg=" + msg + " id=" + (string)id);
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string menu_name = llList2String(parms, 0);
+    string which_choice = llList2String(parms, 1);
+///not used:    key av_key = llList2String(parms, 2);
+//hmmm: should the menutini also offer av name and key options???
+    react_to_menu(menu_name, _private_global_av_name,
+        _private_global_av_key, which_choice);
+}
+
+//////////////
+
+// gives a present to the avatar named here.
+give_gift(string av_name, string av_key, string present)
+{
+//log_it("trying to give a gift of " + present + " to " + av_name);
+    if (av_name != "ALL") {
+        llGiveInventory(av_key, present);
+        llOwnerSay("gave " + present + " to " + av_name);
+    } else {
+        // send the request back to the sensor plugin for processing.
+        llMessageLinked(LINK_ROOT, SENSOR_PLUGIN_HUFFWARE_ID,
+            GIVE_ALL_AVATARS, wrap_parameters([present]));
+    }
+}
+        
+handle_chosen_menu_item(string menu_name, string av_name,
+    string av_key, string which_choice)
+{
+    if (menu_name == GIFTING_MENU_NAME) {
+        give_gift(av_name, av_key, which_choice);
+    }
+
+    // send the alert to the driver.
+    llMessageLinked(LINK_ROOT, MENU_LIST_MANAGER_HUFFWARE_ID + REPLY_DISTANCE,
+        MENU_LIST_MGR_CHOICE_MADE_ALERT,
+        wrap_parameters([which_choice, menu_name, av_name, av_key]));
+}
+
+//////////////
+// from hufflets...
+//
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+integer find_substring(string full_string, string pattern)
+{
+    string full_lower = llToLower(full_string);
+    return llSubStringIndex(full_lower, pattern);
+}
+
+//////////////
+
+// returns the position of the last space in "look_within" or a negative number.
+integer find_last_space(string look_within)
+{
+    integer indy = llStringLength(look_within) - 1;
+    while ( (indy >= 0) && (llGetSubString(look_within, indy, indy) != " ") ) indy--;
+    return indy;
+}
+
+// returns the first name for an avatar with the "full_name".
+string first_name(string full_name)
+{
+    integer finding = find_last_space(full_name);
+    if (finding >= 0) return llGetSubString(full_name, 0, finding - 1);
+    return full_name;  // failed to find space.
+}
+
+// returns the last name for an avatar with the "full_name".
+string last_name(string full_name)
+{
+    integer finding = find_last_space(full_name);
+    if (finding >= 0) return llGetSubString(full_name, finding + 1, -1);
+    return full_name;  // failed to find space.
+}
+
+// substitutes a variable's name for its value.  note that variables are assumed to start
+// with a dollar sign character, which should not be provided in the "variable_name" parameter.
+string substitute_variable(string substitute_within, string variable_name, string variable_value)
+{
+    string to_return = substitute_within;
+    integer posn;
+    while ( (posn = find_substring(to_return, "$" + variable_name)) >= 0) {
+        // we found an occurrence of the variable.
+        to_return = llDeleteSubString(to_return, posn, -1)  // keep part before.
+            + variable_value  // add the value in place of the variable name.
+            + llDeleteSubString(to_return, 0, posn + llStringLength(variable_name));
+                // keep part after.
+    }
+    return to_return;
+}
+
+// in "substitute_within", this finds any occurrences of items in the "variables_names"
+// and replaces those with the corresponding item from "variable_values".
+string substitute_variable_list(string substitute_within, list variable_names, list variable_values)
+{
+    string to_return = substitute_within;
+    integer vars = llGetListLength(variable_names);
+    if (vars != llGetListLength(variable_values)) {
+//        log_it("error in substitute_variable_list: inequal number of variable names vs. values.");
+        return to_return;
+    }
+    integer indy;
+    for (indy = 0; indy < vars; indy++) {
+        to_return = substitute_variable(to_return,
+            llList2String(variable_names, indy),
+            llList2String(variable_values, indy));
+    }
+    return to_return;
+}
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// removes the entry at "index" and instead inserts the list "to_insert"
+// at that position.
+list replace_entry(list to_modify, integer index, list to_insert)
+{
+    if (llGetListLength(to_modify) == 0) return to_insert;  // special case for empty.
+    return llListReplaceList(to_modify, to_insert, index, index);
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+//
+// end hufflets
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();  // make sure newest addition is only version of script.
+        // reset all our variables.
+        menu_names = [];
+        menu_titles = [];
+        menu_button_lists = [];
+        _private_global_av_name = "";
+        _private_global_av_key = NULL_KEY;
+    }
+
+    link_message(integer sender, integer num, string msg, key id)
+    { handle_link_message(sender, num, msg, id); }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/menu_list_manager_v12.4.txt b/huffware/huffotronic_updater_freebie_v5.3/menu_list_manager_v12.4.txt
deleted file mode 100755 (executable)
index 22ddbe4..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-
-// huffware script: menu list manager, by fred huffhines.
-//
-// deals with popping up menus when desired.  does not do any configuration
-// reading; that all must be fed to the script via link messages.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants...
-
-string GIFTING_MENU_NAME = "#gifting#";
-    // the menu name that we support internally for giving gifts.
-
-// global variables...
-
-// these are the definition of the menuing system,
-// and are valid once we have heard our config.
-
-// unique identifiers of menu names.
-list menu_names;
-// a list of titles for the menus.
-list menu_titles;
-// the menu choices are strings containing encoded lists of button text labels.
-list menu_button_lists;
-
-// store current activated menu info...
-string _private_global_av_name;
-string _private_global_av_key;
-
-// menu list manager link message API.
-//////////////
-// do not redefine these constants.
-integer MENU_LIST_MANAGER_HUFFWARE_ID = 10033;
-    // the unique id within the huffware system for this sensor plugin script.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string MENU_LIST_MGR_RESET = "#ml-reset#";
-    // throws out any current menus and gets ready to load a new set.
-string MENU_LIST_MGR_ADD_MENU = "#ml-addmenu#";
-    // puts a new menu into our list.  this requires 3 parameters: menu name,
-    // menu title, menu button list.
-string MENU_LIST_MGR_SHOW_MENU = "#ml-shomenu#";
-    // a request that a particular menu be shown.  the first parameter is the menu index.
-    // the second parameter is the avatar name.  the third parameter is the avatar key.
-string MENU_LIST_MGR_GIVE_ITEM = "#ml-give#";
-    // brings up a gift giving menu.  parms are avatar name and avatar key.
-string MENU_LIST_MGR_MODIFY_MENU = "#ml-modmenu#";
-string MENU_LIST_KEEP_WORD = "KEEP";
-    // replaces a menu already in the list.  this requires 4 parameters: menu index, menu name,
-    // menu title, menu button list.  if a parameter is the MENU_LIST_KEEP_WORD, then that field
-    // is not changed.
-string MENU_LIST_MGR_CHOICE_MADE_ALERT = "#ml-event-picked";
-    // alerts the driver for this script that the owner has picked a choice.  the
-    // parameters include: the text of the choice, the name of the menu, the avatar name,
-    // the avatar key.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// requires HUD sensor plugin v21.4 or better.
-//////////////
-// do not redefine these constants.
-integer SENSOR_PLUGIN_HUFFWARE_ID = 10014;
-    // the unique id within the huffware system for this sensor plugin script.
-string GIVE_ALL_AVATARS = "#santa#";
-    // if this is received, the sensor plugin attempts to hand out an object passed as
-    // the first parameter to every avatar it knows about.
-//////////////
-
-// requires menutini v3.9 or better...
-//////////////
-// do not redefine these constants.
-integer MENUTINI_HUFFWARE_ID = 10009;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-// commands available via menutini:
-string SHOW_MENU_COMMAND = "#menu#";
-    // the command that tells menutini to show a menu defined by parameters
-    // that are passed along.  these must be: the menu name, the menu's title
-    // (which is really the info to show as content in the main box of the menu),
-    // the wrapped list of commands to show as menu buttons, the menu system
-    // channel's for listening, and the key to listen to.
-//
-//////////////
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-//
-//////////////
-
-// replaces occurences of $owner and $avatar with the owner's name and the
-// targeted avatars name.  _first and _last added to the name cause the first
-// or last name to be used instead.
-string senso_substitute_vars(string to_substitute, string avatars_name)
-{
-    string owners_name = llKey2Name(llGetOwner());
-    return substitute_variable_list(to_substitute,
-        [ "avatar_first", "avatar_last", "avatar",
-            "owner_first", "owner_last", "owner" ],
-        [ first_name(avatars_name), last_name(avatars_name), avatars_name,
-           first_name(owners_name), last_name(owners_name), owners_name ]);
-}
-
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-
-simply_display_menu(string menu_name, string title, list buttons,
-    string av_name, string av_key)
-{
-    // we only manage one global now for this stuff...
-    _private_global_av_name = av_name;
-    _private_global_av_key = av_key;
-
-    integer menu_channel = random_channel();
-    key listen_to = llGetOwner();
-//log_it("passing in key to use: " + (string)listen_to);
-    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
-        menu_name + HUFFWARE_PARM_SEPARATOR
-        + title + HUFFWARE_PARM_SEPARATOR
-        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
-        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
-        + (string)listen_to);
-}
-
-replace_vars_and_display_menu(integer menu_index, string av_name, string av_key)
-{
-    // patch the avatar names and owner names before displaying.
-    string title = senso_substitute_vars(llList2String(menu_titles, menu_index), av_name);
-    string button_text = llList2String(menu_button_lists, menu_index);
-
-    simply_display_menu(llList2String(menu_names, menu_index), title,
-        llParseString2List(button_text, [HUFFWARE_ITEM_SEPARATOR], []),
-        av_name, av_key);
-}
-
-// shows a menu by index.
-show_menu(integer index, string av_name, string av_key)
-{
-    replace_vars_and_display_menu(index, av_name, av_key);
-//log_it("sent the menu request...  memory left=" + (string)llGetFreeMemory());
-}
-
-// handles the response message when the user chooses a button.
-react_to_menu(string menu_name, string av_name, string av_key, string which_choice)
-{
-//log_it("you clicked " + which_choice + " item for av " + av_name);
-    handle_chosen_menu_item(menu_name, av_name, av_key, which_choice);
-}
-
-// the gift giving menu.  we show the menu after looking through the
-// inventory.  if the owner picks an item, we'll deal with that response.
-show_gift_menu(string av_name, string av_key)
-{
-    string menu_name = "gift";
-    string menu_title = "Pick a gift for " + av_name + "...";
-    list menu_button_list = [];
-    integer indy;
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_OBJECT); indy++) {
-        menu_button_list += llGetInventoryName(INVENTORY_OBJECT, indy);
-    }
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_TEXTURE); indy++) {
-        string item_name = llGetInventoryName(INVENTORY_TEXTURE, indy);
-        if (!is_prefix(item_name, "ean hud keys"))
-            menu_button_list += item_name;
-    }
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_LANDMARK); indy++) {
-        menu_button_list += llGetInventoryName(INVENTORY_LANDMARK, indy);
-    }
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_NOTECARD); indy++) {
-        string item_name = llGetInventoryName(INVENTORY_NOTECARD, indy);
-        if ( (find_substring(item_name, "help") < 0)
-            && (find_substring(item_name, "Help") < 0)
-            && (find_substring(item_name, "config") < 0) )
-            menu_button_list += item_name;
-    }
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_CLOTHING); indy++) {
-        menu_button_list += llGetInventoryName(INVENTORY_CLOTHING, indy);
-    }
-    for (indy = 0; indy < llGetInventoryNumber(INVENTORY_GESTURE); indy++) {
-        menu_button_list += llGetInventoryName(INVENTORY_GESTURE, indy);
-    }
-    
-    if (llGetListLength(menu_button_list) == 0) {
-        llOwnerSay("There are no objects loaded in the hud currently.  I can make no gifts.");
-    }
-    simply_display_menu(GIFTING_MENU_NAME, menu_title, menu_button_list,
-        av_name, av_key);
-}
-
-// handles a request for this library itself.
-process_hud_menu_mgr_request(integer sender, integer num, string msg, key id)
-{
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    if (msg == MENU_LIST_MGR_RESET) {
-        llResetScript();
-    } else if (msg == MENU_LIST_MGR_ADD_MENU) {
-        if (llGetListLength(parms) < 3) {
-            log_it("too few parms to add menu.");
-            return;
-        }
-//hmmm: sloppy list processing!
-        menu_names += [ llList2String(parms, 0) ];
-        menu_titles += [ llList2String(parms, 1) ];
-        menu_button_lists += [ llList2String(parms, 2) ];
-    } else if (msg == MENU_LIST_MGR_GIVE_ITEM) {
-        // give over a gift.
-        string av_name = llList2String(parms, 0);
-        string av_key = llList2String(parms, 1);
-        show_gift_menu(av_name, av_key);
-    } else if (msg == MENU_LIST_MGR_SHOW_MENU) {
-        if (llGetListLength(parms) < 3) {
-            log_it("too few parms to show menu.");
-            return;
-        }
-//log_it("key comes as " + llList2String(parms, 2));
-        show_menu((integer)llList2String(parms, 0), llList2String(parms, 1),
-            (key)llList2String(parms, 2));
-//log_it("show menu...  memory left=" + (string)llGetFreeMemory());
-    } else if (msg == MENU_LIST_MGR_MODIFY_MENU) {
-        if (llGetListLength(parms) < 4) {
-            log_it("too few parms to replace menu.");
-            return;
-        }
-        integer indo = (integer)llList2String(parms, 0);
-//log_it("modif menu request, indo is " + (string)indo);
-        if (indo >= llGetListLength(menu_names)) {
-//log_it("index too large in replace menu");
-            return;
-        }
-//log_it("replacing entry " + (string)indo + " with " + llList2String(parms, 1) + ", " + llList2String(parms, 2) + ", " + llList2String(parms, 3));
-        if (llList2String(parms, 1) != MENU_LIST_KEEP_WORD)
-            menu_names = replace_entry(menu_names, indo, [ llList2String(parms, 1) ]);
-        if (llList2String(parms, 2) != MENU_LIST_KEEP_WORD)
-            menu_titles = replace_entry(menu_titles, indo, [ llList2String(parms, 2) ]);
-        if (llList2String(parms, 3) != MENU_LIST_KEEP_WORD)
-            menu_button_lists = replace_entry(menu_button_lists, indo, [ llList2String(parms, 3) ]);
-//log_it("new menu button:" + llList2String(parms, 3));
-    }
-}
-
-// processes a message from a link.  some of this must be handled
-// by the driver script that handles our configuration.
-handle_link_message(integer sender, integer num, string msg, key id)
-{
-    if (num == MENU_LIST_MANAGER_HUFFWARE_ID) {
-        process_hud_menu_mgr_request(sender, num, msg, id);
-    }
-    
-    if ( (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE)
-        || (msg != SHOW_MENU_COMMAND) ) return;  // not for us.
-
-//log_it("menu reply: sndr=" + (string)sender + " num=" + (string)num + " msg=" + msg + " id=" + (string)id);
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string menu_name = llList2String(parms, 0);
-    string which_choice = llList2String(parms, 1);
-///not used:    key av_key = llList2String(parms, 2);
-//hmmm: should the menutini also offer av name and key options???
-    react_to_menu(menu_name, _private_global_av_name,
-        _private_global_av_key, which_choice);
-}
-
-//////////////
-
-// gives a present to the avatar named here.
-give_gift(string av_name, string av_key, string present)
-{
-//log_it("trying to give a gift of " + present + " to " + av_name);
-    if (av_name != "ALL") {
-        llGiveInventory(av_key, present);
-        llOwnerSay("gave " + present + " to " + av_name);
-    } else {
-        // send the request back to the sensor plugin for processing.
-        llMessageLinked(LINK_ROOT, SENSOR_PLUGIN_HUFFWARE_ID,
-            GIVE_ALL_AVATARS, wrap_parameters([present]));
-    }
-}
-        
-handle_chosen_menu_item(string menu_name, string av_name,
-    string av_key, string which_choice)
-{
-    if (menu_name == GIFTING_MENU_NAME) {
-        give_gift(av_name, av_key, which_choice);
-    }
-
-    // send the alert to the driver.
-    llMessageLinked(LINK_ROOT, MENU_LIST_MANAGER_HUFFWARE_ID + REPLY_DISTANCE,
-        MENU_LIST_MGR_CHOICE_MADE_ALERT,
-        wrap_parameters([which_choice, menu_name, av_name, av_key]));
-}
-
-//////////////
-// from hufflets...
-//
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-integer find_substring(string full_string, string pattern)
-{
-    string full_lower = llToLower(full_string);
-    return llSubStringIndex(full_lower, pattern);
-}
-
-//////////////
-
-// returns the position of the last space in "look_within" or a negative number.
-integer find_last_space(string look_within)
-{
-    integer indy = llStringLength(look_within) - 1;
-    while ( (indy >= 0) && (llGetSubString(look_within, indy, indy) != " ") ) indy--;
-    return indy;
-}
-
-// returns the first name for an avatar with the "full_name".
-string first_name(string full_name)
-{
-    integer finding = find_last_space(full_name);
-    if (finding >= 0) return llGetSubString(full_name, 0, finding - 1);
-    return full_name;  // failed to find space.
-}
-
-// returns the last name for an avatar with the "full_name".
-string last_name(string full_name)
-{
-    integer finding = find_last_space(full_name);
-    if (finding >= 0) return llGetSubString(full_name, finding + 1, -1);
-    return full_name;  // failed to find space.
-}
-
-// substitutes a variable's name for its value.  note that variables are assumed to start
-// with a dollar sign character, which should not be provided in the "variable_name" parameter.
-string substitute_variable(string substitute_within, string variable_name, string variable_value)
-{
-    string to_return = substitute_within;
-    integer posn;
-    while ( (posn = find_substring(to_return, "$" + variable_name)) >= 0) {
-        // we found an occurrence of the variable.
-        to_return = llDeleteSubString(to_return, posn, -1)  // keep part before.
-            + variable_value  // add the value in place of the variable name.
-            + llDeleteSubString(to_return, 0, posn + llStringLength(variable_name));
-                // keep part after.
-    }
-    return to_return;
-}
-
-// in "substitute_within", this finds any occurrences of items in the "variables_names"
-// and replaces those with the corresponding item from "variable_values".
-string substitute_variable_list(string substitute_within, list variable_names, list variable_values)
-{
-    string to_return = substitute_within;
-    integer vars = llGetListLength(variable_names);
-    if (vars != llGetListLength(variable_values)) {
-//        log_it("error in substitute_variable_list: inequal number of variable names vs. values.");
-        return to_return;
-    }
-    integer indy;
-    for (indy = 0; indy < vars; indy++) {
-        to_return = substitute_variable(to_return,
-            llList2String(variable_names, indy),
-            llList2String(variable_values, indy));
-    }
-    return to_return;
-}
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// removes the entry at "index" and instead inserts the list "to_insert"
-// at that position.
-list replace_entry(list to_modify, integer index, list to_insert)
-{
-    if (llGetListLength(to_modify) == 0) return to_insert;  // special case for empty.
-    return llListReplaceList(to_modify, to_insert, index, index);
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-//
-// end hufflets
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();  // make sure newest addition is only version of script.
-        // reset all our variables.
-        menu_names = [];
-        menu_titles = [];
-        menu_button_lists = [];
-        _private_global_av_name = "";
-        _private_global_av_key = NULL_KEY;
-    }
-
-    link_message(integer sender, integer num, string msg, key id)
-    { handle_link_message(sender, num, msg, id); }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/menutini_library_v5.9.lsl b/huffware/huffotronic_updater_freebie_v5.3/menutini_library_v5.9.lsl
new file mode 100755 (executable)
index 0000000..abd2711
--- /dev/null
@@ -0,0 +1,436 @@
+
+// huffware script: menutini library, by fred huffhines.
+//
+// this is a library script for menuing that provides a way to remote control the
+// menu, somewhat.  another script can zing link messages at this script and a menu
+// will be shown based on the specified description and buttons.  when the user
+// selects an answer, that result is sent back in a link message reply.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// useful constants you might want to change:
+
+integer TIMEOUT_FOR_MENU = 42;
+    // timeout for the menu in seconds.
+//hmmm: may want this to be selectable from menu request.
+//      or may even want to never time out!
+//      if we managed a list of ongoing menus, that would work.
+//      currently it cannot.
+
+integer DEBUGGING = FALSE;
+    // if this is true, then extra info will be printed when handling a menu.
+
+string NEXT_MENU_TEXT = "Next >>";
+    // what the next item will say for showing next menu page.
+
+// menutini link message API...
+//////////////
+// do not redefine these constants.
+integer MENUTINI_HUFFWARE_ID = 10009;
+    // the unique id within the huffware system for the jaunt script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string SHOW_MENU_COMMAND = "#menu#";
+    // the command that tells menutini to show a menu defined by parameters
+    // that are passed along.  these must be: the menu name, the menu's title
+    // (which is really the info to show as content in the main box of the menu),
+    // the wrapped list of commands to show as menu buttons, the menu system
+    // channel's for listening, and the key to listen to.
+    // the reply will include: the menu name, the choice made and the key for
+    // the avatar.
+//
+//////////////
+// joins a list of sub-items using the item sentinel for the library.
+string wrap_item_list(list to_wrap)
+{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
+//
+//////////////
+
+// global variables...
+
+list _private_global_buttons;  // holds onto the active set of menu options.
+string _private_global_av_key;  // the key for the avatar who clicks the menu.
+string _private_global_title;  // holds onto current title text.
+
+integer _menu_base_start = 0;  // position in the items of the current menu.
+
+integer listening_id = 0;
+    // the current id of our listening for the menu.  it's an id returned by LSL
+    // that we need to track so we can cancel the listen.
+
+integer menu_system_channel = 0;
+    // messages come back to us from this channel when user clicks the dialog.
+    // this is set later and the default is meaningless.
+
+string global_menu_name = "";
+    // hangs onto the current menu's name.
+
+//hmmm: note; to manage multiple concurrent menus on different channels,
+//      we must make these into lists.  then the timeouts should apply
+//      individually to these instead of overall (if we even do timeouts;
+//      it's nicer if menus never stop being active).
+
+
+// displays the menu requested.  it's "menu_name" is an internal name that is
+// not displayed to the user.  the "title" is the content shown in the main area
+// of the menu.  "commands_in" is the list of menu items to show as buttons.
+// the "menu_channel" is where the user's clicked response will be sent.  the
+// "listen_to" key is the avatar expected to click the menu, which is needed to
+// listen to his response.
+show_menu(string menu_name, string title, list buttons,
+    integer menu_channel, key listen_to)
+{
+    // save our new parms.
+    global_menu_name = menu_name;
+    _private_global_title = title;
+    _private_global_buttons = buttons;
+    menu_system_channel = menu_channel;
+    _private_global_av_key = listen_to;
+    if (DEBUGGING) {
+        log_it("menu name: " + global_menu_name);
+        log_it("title: " + _private_global_title);
+        log_it("buttons: " + (string)buttons);
+        log_it("channel: " + (string)menu_system_channel);
+        log_it("listen key: " + (string)listen_to);
+    }
+
+    integer add_next = FALSE;  // true if we should add a next menu item.
+
+    // the math here incorporates current button position.
+    integer current = _menu_base_start;
+    integer max_buttons = llGetListLength(buttons) - current;
+
+    if (max_buttons > 12) {
+        // limitation of SL: menus have a max of 12 buttons.
+        max_buttons = 12;
+        add_next = TRUE;
+    } else if (llGetListLength(buttons) > 12) {
+        // we already have been adding next.  let's make sure this gets
+        // a wrap-around next button.
+        add_next = TRUE;
+    }
+    // chop out what we can use in a menu.
+    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
+    if (add_next) {
+        // we were asked to add a menu item for the next screen.
+        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
+    }
+
+    listening_id = llListen(menu_channel, "", listen_to, "");
+    list commands;
+    integer i;
+    // take only the prefix of the string, to avoid getting a length complaint.
+    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
+        string curr = llList2String(trunc_buttons, i);
+        integer last_pos = 23;  // default maximum, highest possible is 24.
+        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
+        curr = llGetSubString(curr, 0, last_pos);
+        commands += curr;
+    }
+    llDialog(listen_to, title, commands, menu_channel);
+    llSetTimerEvent(TIMEOUT_FOR_MENU);
+}
+
+// shuts down any connection we might have had with any active menu.  we will not
+// send any responses after this point (although we might already have responded when
+// the user clicked the menu).
+clear_menu()
+{
+    llListenRemove(listening_id);
+    llSetTimerEvent(0.0);
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+// ours do differ from normal in that we send back the channel as the number parameter
+// instead of enforcing that being MENU_HUFFWARE_ID.
+send_reply(integer destination, integer channel, list parms, string command)
+{
+    llMessageLinked(destination, channel, command,
+        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+// processes the menu requests.
+handle_link_message(integer sender, integer huff_id, string msg, key id)
+{
+    if (huff_id != MENUTINI_HUFFWARE_ID) return;  // not for us.
+
+    if (msg == SHOW_MENU_COMMAND) {
+        _menu_base_start = 0;  // reset the position in the menus.
+        // separate the list out.
+//log_it("id showing: " + id);
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+        // toss any existing menu info.
+        clear_menu();
+//log_it("key here early: " + llList2String(parms, 4));
+        show_menu(llList2String(parms, 0), llList2String(parms, 1),
+            llParseString2List(llList2String(parms, 2),
+                [HUFFWARE_ITEM_SEPARATOR], []),
+            (integer)llList2String(parms, 3),
+            (key)llList2String(parms, 4));
+    }
+}
+
+// process the response when the user chooses a menu item.  this causes our
+// caller to be told what was selected.
+process_menu_response(integer channel, string name, key id, string message)
+{
+    if (channel != menu_system_channel) return;  // not for us.
+
+    if (message == NEXT_MENU_TEXT) {
+        // this is the special choice, so we need to go to the next page.
+        _menu_base_start += 11;
+        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
+            // we have wrapped around the list.  go to the start again.
+            _menu_base_start = 0;
+        }
+        show_menu(global_menu_name, _private_global_title,
+            _private_global_buttons, menu_system_channel,
+            _private_global_av_key);
+        return;  // handled by opening a new menu.
+    }
+    
+    string calculated_name;
+    integer indy;
+    // first try for an exact match.
+    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+        string curr = llList2String(_private_global_buttons, indy);
+        if (curr == message) {
+            // correct the answer based on the full button string.
+            calculated_name = curr;
+        }
+    }
+    if (calculated_name == "") {
+        // try an imprecise match if the exact matching didn't work.
+        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+            string curr = llList2String(_private_global_buttons, indy);
+            if (is_prefix(curr, message)) {
+                // correct the answer based on the full button string.
+                calculated_name = curr;
+            }
+        }
+    }
+    if (calculated_name != "") {
+        // only send a response if that menu choice made sense to us.
+        send_reply(LINK_THIS, MENUTINI_HUFFWARE_ID + REPLY_DISTANCE,
+            [ global_menu_name, calculated_name, _private_global_av_key ],
+            SHOW_MENU_COMMAND);
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+//////////////
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//hmmm: extract this code to a menutini example!
+
+//////////////
+// how to invoke a menu (assuming menutini is in same prim as calling script):
+//
+list buttons;  // holds onto the set of menu options.
+//
+integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
+//
+example_invocation()
+{
+    string menu_name = "grumfazoid";
+    string title = "These united colors of ben's futon have unfortunately run.";
+    buttons = [ "garp out", "sklonar", "fuzzlenog" ];
+    integer menu_channel = random_channel();
+    key listen_to = llGetOwner();
+    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
+        menu_name + HUFFWARE_PARM_SEPARATOR
+        + title + HUFFWARE_PARM_SEPARATOR
+        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
+        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
+        + (string)listen_to);
+}
+//
+// how to handle the response message when the user chooses a button.
+//
+react_to_menu(string menu_name, string which_choice)
+{
+    // one might use the menu_name when dealing with multiple different menus.
+
+    integer indy = 0;
+    // find the specified item and process it.
+    while (indy < llGetListLength(buttons)) {
+        // see if the current destination matches.
+        if (llSubStringIndex(llList2String(buttons, indy), which_choice) == 0) {
+            // this is the chosen item.
+//            process_menu_item(indy);  // using numerical numbering.
+// this function must be implemented in your own code; it is what handles the
+// user picking a particular button on the menu.
+            return;            
+        }
+        indy++;
+    }
+    llSay(0, "did not find menu option");
+}
+
+// an example for menu handling.  this gets the response from menutini library
+// and calls the menu processing method "react_to_menu".
+example_handle_link_message(integer sender, integer num, string msg, key id)
+{
+    if (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) return;  // not for us.
+    if (msg != SHOW_MENU_COMMAND) return;  // also not for us.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string menu_name = llList2String(parms, 0);
+    string which_choice = llList2String(parms, 1);
+    react_to_menu(menu_name, which_choice);
+}
+
+// then inside a state, you need an event handler like so:
+//
+// link_message(integer sender, integer num, string msg, key id)
+// { example_handle_link_message(sender, num, msg, id); }
+
+//
+// end invocation sample code...
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); }
+
+    link_message(integer sender, integer huff_id, string msg, key id)
+    { handle_link_message(sender, huff_id, msg, id); }
+
+    listen(integer channel, string name, key id, string message)
+    { process_menu_response(channel, name, id, message); }
+    
+    // if the timer goes off, then the user has ignored the menu for longer than the
+    // timeout.  we need to turn off our listen and ignore that menu.
+    timer() { clear_menu(); }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/menutini_library_v5.9.txt b/huffware/huffotronic_updater_freebie_v5.3/menutini_library_v5.9.txt
deleted file mode 100755 (executable)
index abd2711..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-
-// huffware script: menutini library, by fred huffhines.
-//
-// this is a library script for menuing that provides a way to remote control the
-// menu, somewhat.  another script can zing link messages at this script and a menu
-// will be shown based on the specified description and buttons.  when the user
-// selects an answer, that result is sent back in a link message reply.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// useful constants you might want to change:
-
-integer TIMEOUT_FOR_MENU = 42;
-    // timeout for the menu in seconds.
-//hmmm: may want this to be selectable from menu request.
-//      or may even want to never time out!
-//      if we managed a list of ongoing menus, that would work.
-//      currently it cannot.
-
-integer DEBUGGING = FALSE;
-    // if this is true, then extra info will be printed when handling a menu.
-
-string NEXT_MENU_TEXT = "Next >>";
-    // what the next item will say for showing next menu page.
-
-// menutini link message API...
-//////////////
-// do not redefine these constants.
-integer MENUTINI_HUFFWARE_ID = 10009;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string SHOW_MENU_COMMAND = "#menu#";
-    // the command that tells menutini to show a menu defined by parameters
-    // that are passed along.  these must be: the menu name, the menu's title
-    // (which is really the info to show as content in the main box of the menu),
-    // the wrapped list of commands to show as menu buttons, the menu system
-    // channel's for listening, and the key to listen to.
-    // the reply will include: the menu name, the choice made and the key for
-    // the avatar.
-//
-//////////////
-// joins a list of sub-items using the item sentinel for the library.
-string wrap_item_list(list to_wrap)
-{ return llDumpList2String(to_wrap, HUFFWARE_ITEM_SEPARATOR); }
-//
-//////////////
-
-// global variables...
-
-list _private_global_buttons;  // holds onto the active set of menu options.
-string _private_global_av_key;  // the key for the avatar who clicks the menu.
-string _private_global_title;  // holds onto current title text.
-
-integer _menu_base_start = 0;  // position in the items of the current menu.
-
-integer listening_id = 0;
-    // the current id of our listening for the menu.  it's an id returned by LSL
-    // that we need to track so we can cancel the listen.
-
-integer menu_system_channel = 0;
-    // messages come back to us from this channel when user clicks the dialog.
-    // this is set later and the default is meaningless.
-
-string global_menu_name = "";
-    // hangs onto the current menu's name.
-
-//hmmm: note; to manage multiple concurrent menus on different channels,
-//      we must make these into lists.  then the timeouts should apply
-//      individually to these instead of overall (if we even do timeouts;
-//      it's nicer if menus never stop being active).
-
-
-// displays the menu requested.  it's "menu_name" is an internal name that is
-// not displayed to the user.  the "title" is the content shown in the main area
-// of the menu.  "commands_in" is the list of menu items to show as buttons.
-// the "menu_channel" is where the user's clicked response will be sent.  the
-// "listen_to" key is the avatar expected to click the menu, which is needed to
-// listen to his response.
-show_menu(string menu_name, string title, list buttons,
-    integer menu_channel, key listen_to)
-{
-    // save our new parms.
-    global_menu_name = menu_name;
-    _private_global_title = title;
-    _private_global_buttons = buttons;
-    menu_system_channel = menu_channel;
-    _private_global_av_key = listen_to;
-    if (DEBUGGING) {
-        log_it("menu name: " + global_menu_name);
-        log_it("title: " + _private_global_title);
-        log_it("buttons: " + (string)buttons);
-        log_it("channel: " + (string)menu_system_channel);
-        log_it("listen key: " + (string)listen_to);
-    }
-
-    integer add_next = FALSE;  // true if we should add a next menu item.
-
-    // the math here incorporates current button position.
-    integer current = _menu_base_start;
-    integer max_buttons = llGetListLength(buttons) - current;
-
-    if (max_buttons > 12) {
-        // limitation of SL: menus have a max of 12 buttons.
-        max_buttons = 12;
-        add_next = TRUE;
-    } else if (llGetListLength(buttons) > 12) {
-        // we already have been adding next.  let's make sure this gets
-        // a wrap-around next button.
-        add_next = TRUE;
-    }
-    // chop out what we can use in a menu.
-    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
-    if (add_next) {
-        // we were asked to add a menu item for the next screen.
-        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
-    }
-
-    listening_id = llListen(menu_channel, "", listen_to, "");
-    list commands;
-    integer i;
-    // take only the prefix of the string, to avoid getting a length complaint.
-    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
-        string curr = llList2String(trunc_buttons, i);
-        integer last_pos = 23;  // default maximum, highest possible is 24.
-        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
-        curr = llGetSubString(curr, 0, last_pos);
-        commands += curr;
-    }
-    llDialog(listen_to, title, commands, menu_channel);
-    llSetTimerEvent(TIMEOUT_FOR_MENU);
-}
-
-// shuts down any connection we might have had with any active menu.  we will not
-// send any responses after this point (although we might already have responded when
-// the user clicked the menu).
-clear_menu()
-{
-    llListenRemove(listening_id);
-    llSetTimerEvent(0.0);
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-// ours do differ from normal in that we send back the channel as the number parameter
-// instead of enforcing that being MENU_HUFFWARE_ID.
-send_reply(integer destination, integer channel, list parms, string command)
-{
-    llMessageLinked(destination, channel, command,
-        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-// processes the menu requests.
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-    if (huff_id != MENUTINI_HUFFWARE_ID) return;  // not for us.
-
-    if (msg == SHOW_MENU_COMMAND) {
-        _menu_base_start = 0;  // reset the position in the menus.
-        // separate the list out.
-//log_it("id showing: " + id);
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-        // toss any existing menu info.
-        clear_menu();
-//log_it("key here early: " + llList2String(parms, 4));
-        show_menu(llList2String(parms, 0), llList2String(parms, 1),
-            llParseString2List(llList2String(parms, 2),
-                [HUFFWARE_ITEM_SEPARATOR], []),
-            (integer)llList2String(parms, 3),
-            (key)llList2String(parms, 4));
-    }
-}
-
-// process the response when the user chooses a menu item.  this causes our
-// caller to be told what was selected.
-process_menu_response(integer channel, string name, key id, string message)
-{
-    if (channel != menu_system_channel) return;  // not for us.
-
-    if (message == NEXT_MENU_TEXT) {
-        // this is the special choice, so we need to go to the next page.
-        _menu_base_start += 11;
-        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
-            // we have wrapped around the list.  go to the start again.
-            _menu_base_start = 0;
-        }
-        show_menu(global_menu_name, _private_global_title,
-            _private_global_buttons, menu_system_channel,
-            _private_global_av_key);
-        return;  // handled by opening a new menu.
-    }
-    
-    string calculated_name;
-    integer indy;
-    // first try for an exact match.
-    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-        string curr = llList2String(_private_global_buttons, indy);
-        if (curr == message) {
-            // correct the answer based on the full button string.
-            calculated_name = curr;
-        }
-    }
-    if (calculated_name == "") {
-        // try an imprecise match if the exact matching didn't work.
-        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-            string curr = llList2String(_private_global_buttons, indy);
-            if (is_prefix(curr, message)) {
-                // correct the answer based on the full button string.
-                calculated_name = curr;
-            }
-        }
-    }
-    if (calculated_name != "") {
-        // only send a response if that menu choice made sense to us.
-        send_reply(LINK_THIS, MENUTINI_HUFFWARE_ID + REPLY_DISTANCE,
-            [ global_menu_name, calculated_name, _private_global_av_key ],
-            SHOW_MENU_COMMAND);
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-//////////////
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//hmmm: extract this code to a menutini example!
-
-//////////////
-// how to invoke a menu (assuming menutini is in same prim as calling script):
-//
-list buttons;  // holds onto the set of menu options.
-//
-integer random_channel() { return -(integer)(llFrand(40000) + 20000); }
-//
-example_invocation()
-{
-    string menu_name = "grumfazoid";
-    string title = "These united colors of ben's futon have unfortunately run.";
-    buttons = [ "garp out", "sklonar", "fuzzlenog" ];
-    integer menu_channel = random_channel();
-    key listen_to = llGetOwner();
-    llMessageLinked(LINK_THIS, MENUTINI_HUFFWARE_ID, SHOW_MENU_COMMAND,
-        menu_name + HUFFWARE_PARM_SEPARATOR
-        + title + HUFFWARE_PARM_SEPARATOR
-        + wrap_item_list(buttons) + HUFFWARE_PARM_SEPARATOR
-        + (string)menu_channel + HUFFWARE_PARM_SEPARATOR
-        + (string)listen_to);
-}
-//
-// how to handle the response message when the user chooses a button.
-//
-react_to_menu(string menu_name, string which_choice)
-{
-    // one might use the menu_name when dealing with multiple different menus.
-
-    integer indy = 0;
-    // find the specified item and process it.
-    while (indy < llGetListLength(buttons)) {
-        // see if the current destination matches.
-        if (llSubStringIndex(llList2String(buttons, indy), which_choice) == 0) {
-            // this is the chosen item.
-//            process_menu_item(indy);  // using numerical numbering.
-// this function must be implemented in your own code; it is what handles the
-// user picking a particular button on the menu.
-            return;            
-        }
-        indy++;
-    }
-    llSay(0, "did not find menu option");
-}
-
-// an example for menu handling.  this gets the response from menutini library
-// and calls the menu processing method "react_to_menu".
-example_handle_link_message(integer sender, integer num, string msg, key id)
-{
-    if (num != MENUTINI_HUFFWARE_ID + REPLY_DISTANCE) return;  // not for us.
-    if (msg != SHOW_MENU_COMMAND) return;  // also not for us.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string menu_name = llList2String(parms, 0);
-    string which_choice = llList2String(parms, 1);
-    react_to_menu(menu_name, which_choice);
-}
-
-// then inside a state, you need an event handler like so:
-//
-// link_message(integer sender, integer num, string msg, key id)
-// { example_handle_link_message(sender, num, msg, id); }
-
-//
-// end invocation sample code...
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); }
-
-    link_message(integer sender, integer huff_id, string msg, key id)
-    { handle_link_message(sender, huff_id, msg, id); }
-
-    listen(integer channel, string name, key id, string message)
-    { process_menu_response(channel, name, id, message); }
-    
-    // if the timer goes off, then the user has ignored the menu for longer than the
-    // timeout.  we need to turn off our listen and ignore that menu.
-    timer() { clear_menu(); }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/non-script_giver_v2.8.lsl b/huffware/huffotronic_updater_freebie_v5.3/non-script_giver_v2.8.lsl
new file mode 100755 (executable)
index 0000000..07e7c93
--- /dev/null
@@ -0,0 +1,412 @@
+
+// huffware script: non-script giver, by fred huffhines.
+//
+// gives all objects, notecards, etc contained in an object when that object is touched.
+// does not give out scripts, since these are generally not something that should be handed
+// to the customer.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer ONLY_GIVE_TO_OWNER = TRUE;
+    // if this is true, then only the owner will receive a copy of the items.
+
+integer GIVE_UNCOPYABLES = FALSE;
+    // this flag is dangerous when true, because it means that uncopyable objects will still
+    // be handed to the target.  if that target refuses the non-copyable items, then the items
+    // will be lost forever.  that is not so good if you've sold the person a non-copy item.
+
+string EXCLUDED_NOTECARD = "product description";
+    // a special case; if there is a giftorse configuration card, we won't hand that out.
+
+integer DEBUGGING = FALSE;  // set to true for noisier runs.
+
+key first_toucher;  // tracks who clicked on the object to get contents.
+
+// give out pictures, notecards, objects, etc. that are hiding in the object.
+really_give_out_contents(key give_to)
+{
+    list all_to_give = [];  // the set we will hand over in a batch.
+    list uncopyables = [];  // the list we have to do individually.
+    // find out how many items there are.
+    integer count = llGetInventoryNumber(INVENTORY_ALL);
+    // iterate across all the items and add them to the gift list if appropriate.
+    integer indy;
+    for (indy = 0; indy < count; indy++) {
+        string item_name = llGetInventoryName(INVENTORY_ALL, indy);
+        integer type = llGetInventoryType(item_name);
+        if ( (type != INVENTORY_SCRIPT) 
+            && ( (type != INVENTORY_NOTECARD) || (item_name != EXCLUDED_NOTECARD) ) ) {
+            // it's okay to add this item; it's not a script and we are not skipping the special notecard.
+            integer mask = MASK_OWNER;
+            if (!ONLY_GIVE_TO_OWNER) mask = MASK_EVERYONE;
+            integer perms = llGetInventoryPermMask(item_name, mask);
+            if (perms & PERM_COPY) {
+                // a normal object that we can hand out.
+                all_to_give += item_name;
+            } else {
+                uncopyables += item_name;
+            }
+        }
+    }
+    // hand the customer the whole set as one big chunk, named after the object.
+    llGiveInventoryList(give_to, llGetObjectName(), all_to_give);
+
+    // handle any problematic items.  we cannot copy these objects into a category folder,
+    // so we can either not try to copy them (a lot safer) or we can try to deliver them
+    // normally as individual items.  the latter choice is more dangerous, because if the
+    // owner discards these items rather than keeping them, the items will be lost forever!
+    if (llGetListLength(uncopyables) > 0) {
+        string plural = " ";
+        string is_verb = "is ";
+        string third_noun_subj = "it ";
+        string third_noun_obj = "it ";
+        if (llGetListLength(uncopyables) > 1) {
+            plural = "s ";
+            is_verb = "are ";
+            third_noun_subj = "they ";
+            third_noun_obj = "them ";
+        }
+        
+        string uncopyable_message = "will be left inside the object.  To get " + third_noun_obj
+            + ", please copy " + third_noun_obj + "\nmanually from this object into your inventory.";
+        if (GIVE_UNCOPYABLES) {
+            uncopyable_message = "will be moved over to your inventory."
+            + "\nPlease look in your main folders for "
+            + third_noun_obj + "(e.g., in Objects or Textures).";
+        }
+        
+        string failure_message = "The item" + plural
+            + "[" + llDumpList2String(uncopyables, "; ") + "]\n"
+            + is_verb + "not copyable; " + third_noun_subj
+            + uncopyable_message;
+            
+        if (llGetOwner() == give_to) {
+            // the object can be moved to inventory, but not with the category method.
+            llOwnerSay(failure_message);
+        } else {
+            // this seems like a weird case; it will probably just fail anyhow?
+            // if the item's not copyable and you're not the owner of this object,
+            // how can we give it to you?
+            llInstantMessage(give_to, failure_message);
+        }
+        
+        // now that we've announced this weird situation, handle it appropriately.
+        if (GIVE_UNCOPYABLES) {
+            for (indy = 0; indy < llGetListLength(uncopyables); indy++) {
+                string item_name = llList2String(uncopyables, indy);
+                llGiveInventory(give_to, item_name);
+            }
+        }  // otherwise leave them be.
+    }
+}
+
+
+//////////////
+// code borrowed from menutini to raise a menu asking if they actually meant to get all
+// the contents.  an opensim inventory bug makes all the folders look foolish if we
+// do any inventory giving accidentally.
+//////////////
+
+// global variables...
+
+list _private_global_buttons;  // holds onto the active set of menu options.
+string _private_global_av_key;  // the key for the avatar who clicks the menu.
+string _private_global_title;  // holds onto current title text.
+
+integer _menu_base_start = 0;  // position in the items of the current menu.
+
+integer listening_id = 0;
+    // the current id of our listening for the menu.  it's an id returned by LSL
+    // that we need to track so we can cancel the listen.
+
+integer menu_system_channel = -123;
+    // messages come back to us from this channel when user clicks the dialog.
+    // this is set later and the default is meaningless.
+
+string global_menu_name = "";
+    // hangs onto the current menu's name.
+
+//hmmm: note; to manage multiple concurrent menus on different channels,
+//      we must make these into lists.  then the timeouts should apply
+//      individually to these instead of overall (if we even do timeouts;
+//      it's nicer if menus never stop being active).
+
+string NEXT_MENU_TEXT = "Next >>";
+    // what the next item will say for showing next menu page.
+    
+//integer TIMEOUT_FOR_MENU = 42;
+    // timeout for the menu in seconds.
+
+// displays the menu requested.  it's "menu_name" is an internal name that is
+// not displayed to the user.  the "title" is the content shown in the main area
+// of the menu.  "commands_in" is the list of menu items to show as buttons.
+// the "menu_channel" is where the user's clicked response will be sent.  the
+// "listen_to" key is the avatar expected to click the menu, which is needed to
+// listen to his response.
+show_menu(string menu_name, string title, list buttons,
+    integer menu_channel, key listen_to)
+{
+    // save our new parms.
+    global_menu_name = menu_name;
+    _private_global_title = title;
+    _private_global_buttons = buttons;
+    menu_system_channel = menu_channel;
+    _private_global_av_key = listen_to;
+    if (DEBUGGING) {
+        log_it("menu name: " + global_menu_name);
+        log_it("title: " + _private_global_title);
+        log_it("buttons: " + (string)buttons);
+        log_it("channel: " + (string)menu_system_channel);
+        log_it("listen key: " + (string)listen_to);
+    }
+
+    integer add_next = FALSE;  // true if we should add a next menu item.
+
+    // the math here incorporates current button position.
+    integer current = _menu_base_start;
+    integer max_buttons = llGetListLength(buttons) - current;
+
+    if (max_buttons > 12) {
+        // limitation of SL: menus have a max of 12 buttons.
+        max_buttons = 12;
+        add_next = TRUE;
+    } else if (llGetListLength(buttons) > 12) {
+        // we already have been adding next.  let's make sure this gets
+        // a wrap-around next button.
+        add_next = TRUE;
+    }
+    // chop out what we can use in a menu.
+    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
+    if (add_next) {
+        // we were asked to add a menu item for the next screen.
+        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
+    }
+
+    listening_id = llListen(menu_channel, "", listen_to, "");
+    list commands;
+    integer i;
+    // take only the prefix of the string, to avoid getting a length complaint.
+    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
+        string curr = llList2String(trunc_buttons, i);
+        integer last_pos = 23;  // default maximum, highest possible is 24.
+        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
+        curr = llGetSubString(curr, 0, last_pos);
+        commands += curr;
+    }
+    llDialog(listen_to, title, commands, menu_channel);
+}
+
+// shuts down any connection we might have had with any active menu.  we will not
+// send any responses after this point (although we might already have responded when
+// the user clicked the menu).
+clear_menu()
+{
+    llListenRemove(listening_id);
+}
+
+// process the response when the user chooses a menu item.
+process_menu_response(integer channel, string name, key id, string message)
+{
+  if (channel != menu_system_channel) return;  // not for us.
+  
+    if (message == NEXT_MENU_TEXT) {
+        // this is the special choice, so we need to go to the next page.
+        _menu_base_start += 11;
+        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
+            // we have wrapped around the list.  go to the start again.
+            _menu_base_start = 0;
+        }
+        show_menu(global_menu_name, _private_global_title,
+            _private_global_buttons, menu_system_channel,
+            _private_global_av_key);
+        return;  // handled by opening a new menu.
+    }
+    
+    string calculated_name;
+    integer indy;
+    // first try for an exact match.
+    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+        string curr = llList2String(_private_global_buttons, indy);
+        if (curr == message) {
+            // correct the answer based on the full button string.
+            calculated_name = curr;
+        }//////////////[copy starting here...]//////////////
+
+    }
+    if (calculated_name == "") {
+        // try an imprecise match if the exact matching didn't work.
+        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
+            string curr = llList2String(_private_global_buttons, indy);
+            if (is_prefix(curr, message)) {
+                // correct the answer based on the full button string.
+                calculated_name = curr;
+            }
+        }
+    }
+    if (calculated_name == "yes") {
+        // only send a response if that menu choice made sense to us.
+        really_give_out_contents(first_toucher);
+        clear_menu();
+    }
+}
+
+// end from menutini.
+//////////////
+
+
+//////////////
+//
+// borrowed from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { 
+        auto_retire();
+    }
+    
+    on_rez(integer param) { llResetScript(); }
+
+    touch_start(integer num) {
+        first_toucher = llDetectedKey(0);
+        // are we only supposed to give stuff to the owner?
+        if (ONLY_GIVE_TO_OWNER && (first_toucher != llGetOwner()) ) {
+            first_toucher = NULL_KEY;
+            return;  // bail out.
+        }
+        show_menu("askreally", "Would you like a copy of this object's contents?",
+            ["yes", "no"], -18264, first_toucher);
+    }
+
+    listen(integer channel, string name, key id, string message)
+    { process_menu_response(channel, name, id, message); }
+
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/non-script_giver_v2.8.txt b/huffware/huffotronic_updater_freebie_v5.3/non-script_giver_v2.8.txt
deleted file mode 100755 (executable)
index 07e7c93..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-
-// huffware script: non-script giver, by fred huffhines.
-//
-// gives all objects, notecards, etc contained in an object when that object is touched.
-// does not give out scripts, since these are generally not something that should be handed
-// to the customer.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer ONLY_GIVE_TO_OWNER = TRUE;
-    // if this is true, then only the owner will receive a copy of the items.
-
-integer GIVE_UNCOPYABLES = FALSE;
-    // this flag is dangerous when true, because it means that uncopyable objects will still
-    // be handed to the target.  if that target refuses the non-copyable items, then the items
-    // will be lost forever.  that is not so good if you've sold the person a non-copy item.
-
-string EXCLUDED_NOTECARD = "product description";
-    // a special case; if there is a giftorse configuration card, we won't hand that out.
-
-integer DEBUGGING = FALSE;  // set to true for noisier runs.
-
-key first_toucher;  // tracks who clicked on the object to get contents.
-
-// give out pictures, notecards, objects, etc. that are hiding in the object.
-really_give_out_contents(key give_to)
-{
-    list all_to_give = [];  // the set we will hand over in a batch.
-    list uncopyables = [];  // the list we have to do individually.
-    // find out how many items there are.
-    integer count = llGetInventoryNumber(INVENTORY_ALL);
-    // iterate across all the items and add them to the gift list if appropriate.
-    integer indy;
-    for (indy = 0; indy < count; indy++) {
-        string item_name = llGetInventoryName(INVENTORY_ALL, indy);
-        integer type = llGetInventoryType(item_name);
-        if ( (type != INVENTORY_SCRIPT) 
-            && ( (type != INVENTORY_NOTECARD) || (item_name != EXCLUDED_NOTECARD) ) ) {
-            // it's okay to add this item; it's not a script and we are not skipping the special notecard.
-            integer mask = MASK_OWNER;
-            if (!ONLY_GIVE_TO_OWNER) mask = MASK_EVERYONE;
-            integer perms = llGetInventoryPermMask(item_name, mask);
-            if (perms & PERM_COPY) {
-                // a normal object that we can hand out.
-                all_to_give += item_name;
-            } else {
-                uncopyables += item_name;
-            }
-        }
-    }
-    // hand the customer the whole set as one big chunk, named after the object.
-    llGiveInventoryList(give_to, llGetObjectName(), all_to_give);
-
-    // handle any problematic items.  we cannot copy these objects into a category folder,
-    // so we can either not try to copy them (a lot safer) or we can try to deliver them
-    // normally as individual items.  the latter choice is more dangerous, because if the
-    // owner discards these items rather than keeping them, the items will be lost forever!
-    if (llGetListLength(uncopyables) > 0) {
-        string plural = " ";
-        string is_verb = "is ";
-        string third_noun_subj = "it ";
-        string third_noun_obj = "it ";
-        if (llGetListLength(uncopyables) > 1) {
-            plural = "s ";
-            is_verb = "are ";
-            third_noun_subj = "they ";
-            third_noun_obj = "them ";
-        }
-        
-        string uncopyable_message = "will be left inside the object.  To get " + third_noun_obj
-            + ", please copy " + third_noun_obj + "\nmanually from this object into your inventory.";
-        if (GIVE_UNCOPYABLES) {
-            uncopyable_message = "will be moved over to your inventory."
-            + "\nPlease look in your main folders for "
-            + third_noun_obj + "(e.g., in Objects or Textures).";
-        }
-        
-        string failure_message = "The item" + plural
-            + "[" + llDumpList2String(uncopyables, "; ") + "]\n"
-            + is_verb + "not copyable; " + third_noun_subj
-            + uncopyable_message;
-            
-        if (llGetOwner() == give_to) {
-            // the object can be moved to inventory, but not with the category method.
-            llOwnerSay(failure_message);
-        } else {
-            // this seems like a weird case; it will probably just fail anyhow?
-            // if the item's not copyable and you're not the owner of this object,
-            // how can we give it to you?
-            llInstantMessage(give_to, failure_message);
-        }
-        
-        // now that we've announced this weird situation, handle it appropriately.
-        if (GIVE_UNCOPYABLES) {
-            for (indy = 0; indy < llGetListLength(uncopyables); indy++) {
-                string item_name = llList2String(uncopyables, indy);
-                llGiveInventory(give_to, item_name);
-            }
-        }  // otherwise leave them be.
-    }
-}
-
-
-//////////////
-// code borrowed from menutini to raise a menu asking if they actually meant to get all
-// the contents.  an opensim inventory bug makes all the folders look foolish if we
-// do any inventory giving accidentally.
-//////////////
-
-// global variables...
-
-list _private_global_buttons;  // holds onto the active set of menu options.
-string _private_global_av_key;  // the key for the avatar who clicks the menu.
-string _private_global_title;  // holds onto current title text.
-
-integer _menu_base_start = 0;  // position in the items of the current menu.
-
-integer listening_id = 0;
-    // the current id of our listening for the menu.  it's an id returned by LSL
-    // that we need to track so we can cancel the listen.
-
-integer menu_system_channel = -123;
-    // messages come back to us from this channel when user clicks the dialog.
-    // this is set later and the default is meaningless.
-
-string global_menu_name = "";
-    // hangs onto the current menu's name.
-
-//hmmm: note; to manage multiple concurrent menus on different channels,
-//      we must make these into lists.  then the timeouts should apply
-//      individually to these instead of overall (if we even do timeouts;
-//      it's nicer if menus never stop being active).
-
-string NEXT_MENU_TEXT = "Next >>";
-    // what the next item will say for showing next menu page.
-    
-//integer TIMEOUT_FOR_MENU = 42;
-    // timeout for the menu in seconds.
-
-// displays the menu requested.  it's "menu_name" is an internal name that is
-// not displayed to the user.  the "title" is the content shown in the main area
-// of the menu.  "commands_in" is the list of menu items to show as buttons.
-// the "menu_channel" is where the user's clicked response will be sent.  the
-// "listen_to" key is the avatar expected to click the menu, which is needed to
-// listen to his response.
-show_menu(string menu_name, string title, list buttons,
-    integer menu_channel, key listen_to)
-{
-    // save our new parms.
-    global_menu_name = menu_name;
-    _private_global_title = title;
-    _private_global_buttons = buttons;
-    menu_system_channel = menu_channel;
-    _private_global_av_key = listen_to;
-    if (DEBUGGING) {
-        log_it("menu name: " + global_menu_name);
-        log_it("title: " + _private_global_title);
-        log_it("buttons: " + (string)buttons);
-        log_it("channel: " + (string)menu_system_channel);
-        log_it("listen key: " + (string)listen_to);
-    }
-
-    integer add_next = FALSE;  // true if we should add a next menu item.
-
-    // the math here incorporates current button position.
-    integer current = _menu_base_start;
-    integer max_buttons = llGetListLength(buttons) - current;
-
-    if (max_buttons > 12) {
-        // limitation of SL: menus have a max of 12 buttons.
-        max_buttons = 12;
-        add_next = TRUE;
-    } else if (llGetListLength(buttons) > 12) {
-        // we already have been adding next.  let's make sure this gets
-        // a wrap-around next button.
-        add_next = TRUE;
-    }
-    // chop out what we can use in a menu.
-    list trunc_buttons = llList2List(buttons, current, current + max_buttons - 1);
-    if (add_next) {
-        // we were asked to add a menu item for the next screen.
-        trunc_buttons = llList2List(trunc_buttons, 0, 10) + NEXT_MENU_TEXT;
-    }
-
-    listening_id = llListen(menu_channel, "", listen_to, "");
-    list commands;
-    integer i;
-    // take only the prefix of the string, to avoid getting a length complaint.
-    for (i = 0; i < llGetListLength(trunc_buttons); i++) {
-        string curr = llList2String(trunc_buttons, i);
-        integer last_pos = 23;  // default maximum, highest possible is 24.
-        if (llStringLength(curr) - 1 < last_pos) last_pos = llStringLength(curr) - 1;
-        curr = llGetSubString(curr, 0, last_pos);
-        commands += curr;
-    }
-    llDialog(listen_to, title, commands, menu_channel);
-}
-
-// shuts down any connection we might have had with any active menu.  we will not
-// send any responses after this point (although we might already have responded when
-// the user clicked the menu).
-clear_menu()
-{
-    llListenRemove(listening_id);
-}
-
-// process the response when the user chooses a menu item.
-process_menu_response(integer channel, string name, key id, string message)
-{
-  if (channel != menu_system_channel) return;  // not for us.
-  
-    if (message == NEXT_MENU_TEXT) {
-        // this is the special choice, so we need to go to the next page.
-        _menu_base_start += 11;
-        if (_menu_base_start > llGetListLength(_private_global_buttons)) {
-            // we have wrapped around the list.  go to the start again.
-            _menu_base_start = 0;
-        }
-        show_menu(global_menu_name, _private_global_title,
-            _private_global_buttons, menu_system_channel,
-            _private_global_av_key);
-        return;  // handled by opening a new menu.
-    }
-    
-    string calculated_name;
-    integer indy;
-    // first try for an exact match.
-    for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-        string curr = llList2String(_private_global_buttons, indy);
-        if (curr == message) {
-            // correct the answer based on the full button string.
-            calculated_name = curr;
-        }//////////////[copy starting here...]//////////////
-
-    }
-    if (calculated_name == "") {
-        // try an imprecise match if the exact matching didn't work.
-        for (indy = 0; indy < llGetListLength(_private_global_buttons); indy++) {
-            string curr = llList2String(_private_global_buttons, indy);
-            if (is_prefix(curr, message)) {
-                // correct the answer based on the full button string.
-                calculated_name = curr;
-            }
-        }
-    }
-    if (calculated_name == "yes") {
-        // only send a response if that menu choice made sense to us.
-        really_give_out_contents(first_toucher);
-        clear_menu();
-    }
-}
-
-// end from menutini.
-//////////////
-
-
-//////////////
-//
-// borrowed from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { 
-        auto_retire();
-    }
-    
-    on_rez(integer param) { llResetScript(); }
-
-    touch_start(integer num) {
-        first_toucher = llDetectedKey(0);
-        // are we only supposed to give stuff to the owner?
-        if (ONLY_GIVE_TO_OWNER && (first_toucher != llGetOwner()) ) {
-            first_toucher = NULL_KEY;
-            return;  // bail out.
-        }
-        show_menu("askreally", "Would you like a copy of this object's contents?",
-            ["yes", "no"], -18264, first_toucher);
-    }
-
-    listen(integer channel, string name, key id, string message)
-    { process_menu_response(channel, name, id, message); }
-
-}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/noteworthy_library_v12.4.lsl b/huffware/huffotronic_updater_freebie_v5.3/noteworthy_library_v12.4.lsl
new file mode 100755 (executable)
index 0000000..4d56bac
--- /dev/null
@@ -0,0 +1,541 @@
+
+// huffware script: noteworthy library, by fred huffhines.
+//
+// a handy approach to reading a notecard.  this version supports requiring
+// a 'signature' in the notecard's first line, so that multiple notecards can
+// exist in an object without being misinterpreted.  the script is accessed via
+// its link message API, so it can be used in an object without all this code
+// needing to be embedded in another script.  it also supports queuing up requests
+// to read notecards, so multiple scripts can use it to read their specific
+// notecards without any special handling (besides waiting a bit longer).
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants that can be adapted to your needs...
+
+integer DEBUGGING = FALSE;
+    // if this is true, then a lot of extra noise is generated when notecards are read.
+
+float TIME_OUT_ON_ONE_NOTECARD = 42.0;
+    // we allow one line of a notecard this long to be read before we decide it's hosed.
+    // some sims are very very slow, and a time-out of one minute has been found lacking;
+    // we saw at least one case where the first notecard line to be read took longer than
+    // 60 seconds.  that's why we kept cranking this time-out up...
+
+// constants that should not be changed...
+
+// outcomes from handling a line in a notecard.
+integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
+integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
+integer DONE_READING = -10;  // the notecard is finished being read.
+
+integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
+
+integer MAXIMUM_LINES_USED = 4;
+    // we will read this many lines at a time from the appropriate notecard.
+
+// this is the noteworthy library's API that is available via link messages.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+string BAD_NOTECARD_INDICATOR = "bad_notecard";
+    // indicates that the notecard reading process has failed to find an appropriate one.
+    
+//STRIKE THIS from everywhere.
+//string BUSY_READING_INDICATOR = "busy_already";
+//    // this return value indicates that the script is already in use by some other script.
+//    // the calling script should try again later.
+
+string NOTECARD_READ_CONTINUATION = "continue!";
+    // returned as first parameter if there is still more data to handle.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be blank.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
+    // found) and as subsequent elements an embedded list that was read from the
+    // notecard.  this necessarily limits the size of the notecards that we can read
+    // and return.
+string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
+    // like the read notecard command, but specifies the notecard name to use.  only that
+    // specific notecard file will be consulted.  first and second parm are still signature
+    // and response code, third parm is the notecard name.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// global variables...
+
+string requested_signature = "";
+    // if this is non-empty, then it must be found in the first line of the script.
+
+integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
+
+string global_notecard_name;  // the name of the card we're reading now.
+key global_query_id = NULL_KEY;  // the identifier of our data query.
+integer current_response_code = 0;  // the code that our client uses for its reading.
+list global_query_contents;  // the lines we have read from the notecard.
+
+integer line_number = 0;  // which line are we at in notecard?
+
+integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
+
+integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
+
+list pending_signatures;  // signatures from queued requests for reading.
+list pending_response_codes;  // response codes for the queued requests.
+list pending_notecard_names;  // card names if it's a specific request.
+
+//////////////
+
+startup_initialize()
+{
+    pending_signatures = [];
+    pending_response_codes = [];
+    pending_notecard_names = [];
+    current_response_code = 0;
+    llSetTimerEvent(0.0);
+}
+
+reset_for_reading(string signature, integer response_code)
+{
+    requested_signature = signature;
+    current_response_code = response_code;
+    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
+    global_query_contents = [];
+    global_notecard_name = "";
+    line_number = 0;
+    found_signature_line = FALSE;
+    trying_notecard_at = -1;
+    global_query_id = NULL_KEY;
+}
+
+// use the existing global notecard setting to start reading.
+select_specific_notecard()
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    line_number = 0;  // reset line number again.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// picks the notecard at the "index" (from 0 to num_notecards - 1) and
+// starts reading it.
+select_notecard(integer index)
+{
+    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
+    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
+    if (card_specified == "") return;   // not good.  bad index.
+    global_notecard_name = card_specified;
+    line_number = 0;  // reset line number again.
+    // we have a new file name, so load up the destinations, hopefully.
+    global_query_id = llGetNotecardLine(global_notecard_name, 0);
+}
+
+// increments our index in the count of notecards that the object has, and start
+// reading the next notecard (at the index).
+integer try_next_notecard()
+{
+    if (only_read_one_notecard) {
+        return FALSE;  // we were only going to try one.
+    }
+    // reset some values that might have applied before.
+    global_notecard_name = "";
+    // skip to the next card.
+    trying_notecard_at++;
+    // make sure we're not over the count of cards.
+    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
+        // this is a problem.  we didn't find anything suitable.
+        return FALSE;
+    }
+    // so, now we'll try the next notecard to look for our signature.
+    select_notecard(trying_notecard_at);
+    return TRUE;
+}
+
+// process a line of text that we received from the current notecard.
+integer handle_notecard_line(key query_id, string data)
+{
+    // if we're not at the end of the notecard we're reading...
+    if (data != EOF) {
+        // there's more to read in the notecard still.
+        if (data != "") {
+            // make sure we even have a signature to look for.
+            if (!found_signature_line && (requested_signature == "")) {
+                // no signature means that we always find it.
+                found_signature_line = TRUE;
+            }
+            // did we already get our signature?  if not, see if this is it.
+            if (!found_signature_line && (data != requested_signature) ) {
+                // this is a bad notecard.  skip it.
+                if (!try_next_notecard()) {
+                    // we have no more to work with.
+                    return BAD_NOTECARD;
+                }
+                return STILL_READING;  // we'll keep going.
+            } else if (!found_signature_line && (data == requested_signature) ) {
+                // this is a good signature line, so record that and then skip it.
+                found_signature_line = TRUE;
+            } else {
+                if (DEBUGGING
+                    && ( ( (requested_signature == "") && (line_number == 0) )
+                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
+                    log_it("started reading " + global_notecard_name + "...");
+                }
+                // don't record any lines that are comments.
+                if ( (llGetSubString(data, 0, 0) != "#")
+                    && (llGetSubString(data, 0, 0) != ";") ) {
+                    // add the non-blank line to our list.
+                    global_query_contents += data;
+                    // make sure we still have enough space to keep going.
+                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
+                        // ooh, make sure we pause before blowing our heap&stack.
+                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
+                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
+                    }
+                }
+            }
+        }
+        line_number++;  // increase the line count.
+        // reset the timer rather than timing out, if we actually got some data.
+        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
+        // request the next line from the notecard.
+        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
+        if (global_query_id == NULL_KEY) {
+//log_it("failed to restart notecard reading.");
+            return DONE_READING;
+//is that the best outcome?
+        }
+        return STILL_READING;
+    } else {
+        // that's the end of the notecard.  we need some minimal verification that it
+        // wasn't full of garbage.
+        if (!found_signature_line) {
+            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
+            if (!try_next_notecard()) {
+                return BAD_NOTECARD;  // we failed to find a good line?
+            } else {
+                // the next notecard's coming through now.
+                return STILL_READING;
+            }
+        } else {
+//            if (DEBUGGING) log_it("found signature.");
+            // saw the signature line, so this is a good one.
+            return DONE_READING;
+        }
+    }
+}
+
+// only sends reply; does not reset notecard process.
+send_reply(integer destination, list parms, string command,
+    integer include_query)
+{
+//integer items = llGetListLength(parms);
+//if (include_query) items += llGetListLength(global_query_contents);
+//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
+
+   if (!include_query) {
+        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+    } else {
+        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
+            command,
+            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
+    }
+    global_query_contents = [];
+//log_it("post-sending, mem=" + (string)llGetFreeMemory());
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply_and_reset(integer destination, list parms, string command,
+    integer include_query)
+{
+    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
+    send_reply(destination, parms, command, include_query);
+    current_response_code = 0;  // reset back to default so we can start another read.
+    global_query_id = NULL_KEY;  // reset so we accept no more data.
+}
+
+// if there are other pending notecard reads, this goes to the next one listed.
+dequeue_next_request()
+{
+    if (llGetListLength(pending_signatures)) {
+        // get the info from the next pending item.
+        string sig = llList2String(pending_signatures, 0);
+        integer response_code = llList2Integer(pending_response_codes, 0);
+        string notecard = llList2String(pending_notecard_names, 0);
+        // whack the head of the queue since we grabbed the info.
+        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
+        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
+        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
+        if (llStringLength(notecard)) {
+            global_notecard_name = notecard;
+            select_specific_notecard();
+        } else {
+            reset_for_reading(sig, response_code);
+        }
+    }
+}
+
+// deals with one data server answer from the notecard.
+process_notecard_line(key query_id, string data)
+{
+    // try to consume a line from the notecard.
+    integer outcome = handle_notecard_line(query_id, data);
+    if (outcome == DONE_READING) {
+        // that was a valid notecard and we read all of it.
+        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
+        // send back the results.
+        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
+            READ_NOTECARD_COMMAND, TRUE);
+    } else if (outcome == BAD_NOTECARD) {
+        // bail; this problem must be addressed by other means.
+        if (DEBUGGING) log_it("failed to find an appropriate notecard");
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    } else if (outcome == STILL_READING) {
+        // we have a good card and are still processing it.
+        return;
+    } else {
+        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
+        // again, bail out.  we have no idea what happened with this.
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+    }
+    // if we have reached here, we should crank up the next queued notecard reading.
+    dequeue_next_request();
+}
+
+// processes requests from our users.
+handle_link_message(integer which, integer num, string msg, key id)
+{
+    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
+
+    if (msg == READ_NOTECARD_COMMAND) {
+        only_read_one_notecard = FALSE;  // general inquiry for any card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read notecard--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code = llList2Integer(parms, 1);
+//log_it("got signature " + signature + " and respcode " + (string)response_code);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code);
+            if (!try_next_notecard()) {
+                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
+                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code ],
+                    READ_NOTECARD_COMMAND, FALSE);
+                return;
+            }
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code;
+//holding:            pending_notecard_names += "";
+//holding:        }
+    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
+        only_read_one_notecard = TRUE;  // they want one particular card.
+        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+//log_it("read specific--parms are: " + (string)parms);
+        string signature = llList2String(parms, 0);
+        integer response_code = llList2Integer(parms, 1);
+        string notecard_name = llList2String(parms, 2);
+//log_it("got signature " + signature + " and respcode " + (string)response_code);
+//holding:        if (!current_response_code) {
+            // go ahead and process this request; we aren't busy.
+            reset_for_reading(signature, response_code);
+            global_notecard_name = notecard_name;  // set our global.
+            select_specific_notecard();
+//holding:        } else {
+//holding:            // we're already busy.
+//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
+//holding://                READ_NOTECARD_COMMAND, FALSE);
+//holding:            // stack this request; another is in progress.
+//holding:            pending_signatures += signature;
+//holding:            pending_response_codes += response_code;
+//holding:            pending_notecard_names += notecard_name;
+//holding:        }
+    }
+}
+
+
+///////////////
+
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, (string)debug_num + "- " + to_say);
+}
+
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.4.
+// distributed under BSD-like license.
+//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
+// the function auto_retire() should be added *inside* a version numbered script that
+// you wish to give the capability of self-upgrading.
+//   this script supports a notation for versions embedded in script names where a 'v'
+// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
+// when the containing script is dropped into an object with a different version, the
+// most recent version eats any existing ones.
+//   keep in mind that this code must be *copied* into your script you wish to add
+// auto-retirement capability to.
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// end hufflets.
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        startup_initialize();
+    }
+    
+    state_exit() {
+        llSetTimerEvent(0);
+    }
+    
+    // we don't do anything until we're given a command to read a notecard.
+    link_message(integer which, integer num, string msg, key id) 
+    {
+        if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
+        handle_link_message(which, num, msg, id);
+    }
+    
+    on_rez(integer parm) { state rerun; }
+    
+    timer() {
+        llSetTimerEvent(0.0);  // stop any timer now.
+        // let the caller know this has failed out.
+//        if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
+        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
+            READ_NOTECARD_COMMAND, FALSE);
+        current_response_code = 0;  // we gave up on that one.
+        dequeue_next_request();  // get next reading started if we have anything to read.
+    }
+
+    dataserver(key query_id, string data) {
+        // make sure this data is for us.
+        if (global_query_id != query_id) return;
+        // yep, seems to be.
+        process_notecard_line(query_id, data);
+    }
+}
+
+
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/noteworthy_library_v12.4.txt b/huffware/huffotronic_updater_freebie_v5.3/noteworthy_library_v12.4.txt
deleted file mode 100755 (executable)
index 4d56bac..0000000
+++ /dev/null
@@ -1,541 +0,0 @@
-
-// huffware script: noteworthy library, by fred huffhines.
-//
-// a handy approach to reading a notecard.  this version supports requiring
-// a 'signature' in the notecard's first line, so that multiple notecards can
-// exist in an object without being misinterpreted.  the script is accessed via
-// its link message API, so it can be used in an object without all this code
-// needing to be embedded in another script.  it also supports queuing up requests
-// to read notecards, so multiple scripts can use it to read their specific
-// notecards without any special handling (besides waiting a bit longer).
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants that can be adapted to your needs...
-
-integer DEBUGGING = FALSE;
-    // if this is true, then a lot of extra noise is generated when notecards are read.
-
-float TIME_OUT_ON_ONE_NOTECARD = 42.0;
-    // we allow one line of a notecard this long to be read before we decide it's hosed.
-    // some sims are very very slow, and a time-out of one minute has been found lacking;
-    // we saw at least one case where the first notecard line to be read took longer than
-    // 60 seconds.  that's why we kept cranking this time-out up...
-
-// constants that should not be changed...
-
-// outcomes from handling a line in a notecard.
-integer STILL_READING = -8;  // the notecard seems good, but isn't finished.
-integer BAD_NOTECARD = -9;  // this notecard doesn't have our signature.
-integer DONE_READING = -10;  // the notecard is finished being read.
-
-integer LIST_ELEMENT_GUESS = 200;  // guess at how many bytes average list element uses.
-
-integer MAXIMUM_LINES_USED = 4;
-    // we will read this many lines at a time from the appropriate notecard.
-
-// this is the noteworthy library's API that is available via link messages.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-string BAD_NOTECARD_INDICATOR = "bad_notecard";
-    // indicates that the notecard reading process has failed to find an appropriate one.
-    
-//STRIKE THIS from everywhere.
-//string BUSY_READING_INDICATOR = "busy_already";
-//    // this return value indicates that the script is already in use by some other script.
-//    // the calling script should try again later.
-
-string NOTECARD_READ_CONTINUATION = "continue!";
-    // returned as first parameter if there is still more data to handle.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be blank.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or BAD_NOTECARD_INDICATOR if none was
-    // found) and as subsequent elements an embedded list that was read from the
-    // notecard.  this necessarily limits the size of the notecards that we can read
-    // and return.
-string READ_SPECIFIC_NOTECARD_COMMAND = "#read_thisun#";
-    // like the read notecard command, but specifies the notecard name to use.  only that
-    // specific notecard file will be consulted.  first and second parm are still signature
-    // and response code, third parm is the notecard name.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// global variables...
-
-string requested_signature = "";
-    // if this is non-empty, then it must be found in the first line of the script.
-
-integer only_read_one_notecard = FALSE;  // true if just one specific notecard should be used.
-
-string global_notecard_name;  // the name of the card we're reading now.
-key global_query_id = NULL_KEY;  // the identifier of our data query.
-integer current_response_code = 0;  // the code that our client uses for its reading.
-list global_query_contents;  // the lines we have read from the notecard.
-
-integer line_number = 0;  // which line are we at in notecard?
-
-integer found_signature_line = FALSE;  // did we find our first line in a notecard yet?
-
-integer trying_notecard_at = -1;  // where we are currently looking for a good notecard.
-
-list pending_signatures;  // signatures from queued requests for reading.
-list pending_response_codes;  // response codes for the queued requests.
-list pending_notecard_names;  // card names if it's a specific request.
-
-//////////////
-
-startup_initialize()
-{
-    pending_signatures = [];
-    pending_response_codes = [];
-    pending_notecard_names = [];
-    current_response_code = 0;
-    llSetTimerEvent(0.0);
-}
-
-reset_for_reading(string signature, integer response_code)
-{
-    requested_signature = signature;
-    current_response_code = response_code;
-    llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);  // don't allow a read to happen forever.
-    global_query_contents = [];
-    global_notecard_name = "";
-    line_number = 0;
-    found_signature_line = FALSE;
-    trying_notecard_at = -1;
-    global_query_id = NULL_KEY;
-}
-
-// use the existing global notecard setting to start reading.
-select_specific_notecard()
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    line_number = 0;  // reset line number again.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// picks the notecard at the "index" (from 0 to num_notecards - 1) and
-// starts reading it.
-select_notecard(integer index)
-{
-    global_query_id = NULL_KEY;  // reset the query id so we don't get bogus answers.
-    string card_specified = llGetInventoryName(INVENTORY_NOTECARD, index);
-    if (card_specified == "") return;   // not good.  bad index.
-    global_notecard_name = card_specified;
-    line_number = 0;  // reset line number again.
-    // we have a new file name, so load up the destinations, hopefully.
-    global_query_id = llGetNotecardLine(global_notecard_name, 0);
-}
-
-// increments our index in the count of notecards that the object has, and start
-// reading the next notecard (at the index).
-integer try_next_notecard()
-{
-    if (only_read_one_notecard) {
-        return FALSE;  // we were only going to try one.
-    }
-    // reset some values that might have applied before.
-    global_notecard_name = "";
-    // skip to the next card.
-    trying_notecard_at++;
-    // make sure we're not over the count of cards.
-    if (trying_notecard_at >= llGetInventoryNumber(INVENTORY_NOTECARD)) {
-        // this is a problem.  we didn't find anything suitable.
-        return FALSE;
-    }
-    // so, now we'll try the next notecard to look for our signature.
-    select_notecard(trying_notecard_at);
-    return TRUE;
-}
-
-// process a line of text that we received from the current notecard.
-integer handle_notecard_line(key query_id, string data)
-{
-    // if we're not at the end of the notecard we're reading...
-    if (data != EOF) {
-        // there's more to read in the notecard still.
-        if (data != "") {
-            // make sure we even have a signature to look for.
-            if (!found_signature_line && (requested_signature == "")) {
-                // no signature means that we always find it.
-                found_signature_line = TRUE;
-            }
-            // did we already get our signature?  if not, see if this is it.
-            if (!found_signature_line && (data != requested_signature) ) {
-                // this is a bad notecard.  skip it.
-                if (!try_next_notecard()) {
-                    // we have no more to work with.
-                    return BAD_NOTECARD;
-                }
-                return STILL_READING;  // we'll keep going.
-            } else if (!found_signature_line && (data == requested_signature) ) {
-                // this is a good signature line, so record that and then skip it.
-                found_signature_line = TRUE;
-            } else {
-                if (DEBUGGING
-                    && ( ( (requested_signature == "") && (line_number == 0) )
-                        || ( (requested_signature != "") && (line_number == 1) ) ) ) {
-                    log_it("started reading " + global_notecard_name + "...");
-                }
-                // don't record any lines that are comments.
-                if ( (llGetSubString(data, 0, 0) != "#")
-                    && (llGetSubString(data, 0, 0) != ";") ) {
-                    // add the non-blank line to our list.
-                    global_query_contents += data;
-                    // make sure we still have enough space to keep going.
-                    if (llGetListLength(global_query_contents) >= MAXIMUM_LINES_USED) {
-                        // ooh, make sure we pause before blowing our heap&stack.
-                        send_reply(LINK_THIS, [ NOTECARD_READ_CONTINUATION,
-                            current_response_code ], READ_NOTECARD_COMMAND, TRUE);                
-                    }
-                }
-            }
-        }
-        line_number++;  // increase the line count.
-        // reset the timer rather than timing out, if we actually got some data.
-        llSetTimerEvent(TIME_OUT_ON_ONE_NOTECARD);        
-        // request the next line from the notecard.
-        global_query_id = llGetNotecardLine(global_notecard_name, line_number);
-        if (global_query_id == NULL_KEY) {
-//log_it("failed to restart notecard reading.");
-            return DONE_READING;
-//is that the best outcome?
-        }
-        return STILL_READING;
-    } else {
-        // that's the end of the notecard.  we need some minimal verification that it
-        // wasn't full of garbage.
-        if (!found_signature_line) {
-            if (DEBUGGING) log_it("never found signature in " + global_notecard_name);
-            if (!try_next_notecard()) {
-                return BAD_NOTECARD;  // we failed to find a good line?
-            } else {
-                // the next notecard's coming through now.
-                return STILL_READING;
-            }
-        } else {
-//            if (DEBUGGING) log_it("found signature.");
-            // saw the signature line, so this is a good one.
-            return DONE_READING;
-        }
-    }
-}
-
-// only sends reply; does not reset notecard process.
-send_reply(integer destination, list parms, string command,
-    integer include_query)
-{
-//integer items = llGetListLength(parms);
-//if (include_query) items += llGetListLength(global_query_contents);
-//log_it("pre-sending " + (string)items + " items, mem=" + (string)llGetFreeMemory());
-
-   if (!include_query) {
-        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command, llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-    } else {
-        llMessageLinked(destination, NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE,
-            command,
-            llDumpList2String(parms + global_query_contents, HUFFWARE_PARM_SEPARATOR));
-    }
-    global_query_contents = [];
-//log_it("post-sending, mem=" + (string)llGetFreeMemory());
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply_and_reset(integer destination, list parms, string command,
-    integer include_query)
-{
-    llSetTimerEvent(0.0);  // stop the timer, since we're about to reply.
-    send_reply(destination, parms, command, include_query);
-    current_response_code = 0;  // reset back to default so we can start another read.
-    global_query_id = NULL_KEY;  // reset so we accept no more data.
-}
-
-// if there are other pending notecard reads, this goes to the next one listed.
-dequeue_next_request()
-{
-    if (llGetListLength(pending_signatures)) {
-        // get the info from the next pending item.
-        string sig = llList2String(pending_signatures, 0);
-        integer response_code = llList2Integer(pending_response_codes, 0);
-        string notecard = llList2String(pending_notecard_names, 0);
-        // whack the head of the queue since we grabbed the info.
-        pending_signatures = llDeleteSubList(pending_signatures, 0, 0);
-        pending_response_codes = llDeleteSubList(pending_response_codes, 0, 0);
-        pending_notecard_names = llDeleteSubList(pending_notecard_names, 0, 0);
-        if (llStringLength(notecard)) {
-            global_notecard_name = notecard;
-            select_specific_notecard();
-        } else {
-            reset_for_reading(sig, response_code);
-        }
-    }
-}
-
-// deals with one data server answer from the notecard.
-process_notecard_line(key query_id, string data)
-{
-    // try to consume a line from the notecard.
-    integer outcome = handle_notecard_line(query_id, data);
-    if (outcome == DONE_READING) {
-        // that was a valid notecard and we read all of it.
-        if (DEBUGGING) log_it("finished reading " + global_notecard_name + ".");
-        // send back the results.
-        send_reply_and_reset(LINK_THIS, [ global_notecard_name, current_response_code ],
-            READ_NOTECARD_COMMAND, TRUE);
-    } else if (outcome == BAD_NOTECARD) {
-        // bail; this problem must be addressed by other means.
-        if (DEBUGGING) log_it("failed to find an appropriate notecard");
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    } else if (outcome == STILL_READING) {
-        // we have a good card and are still processing it.
-        return;
-    } else {
-        if (DEBUGGING) log_it("unknown outcome from handle_notecard_line");
-        // again, bail out.  we have no idea what happened with this.
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-    }
-    // if we have reached here, we should crank up the next queued notecard reading.
-    dequeue_next_request();
-}
-
-// processes requests from our users.
-handle_link_message(integer which, integer num, string msg, key id)
-{
-    if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
-
-    if (msg == READ_NOTECARD_COMMAND) {
-        only_read_one_notecard = FALSE;  // general inquiry for any card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read notecard--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code = llList2Integer(parms, 1);
-//log_it("got signature " + signature + " and respcode " + (string)response_code);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code);
-            if (!try_next_notecard()) {
-                if (DEBUGGING) log_it("failed to find any appropriate notecards at all.");
-                send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, response_code ],
-                    READ_NOTECARD_COMMAND, FALSE);
-                return;
-            }
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code;
-//holding:            pending_notecard_names += "";
-//holding:        }
-    } else if (msg == READ_SPECIFIC_NOTECARD_COMMAND) {
-        only_read_one_notecard = TRUE;  // they want one particular card.
-        list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-//log_it("read specific--parms are: " + (string)parms);
-        string signature = llList2String(parms, 0);
-        integer response_code = llList2Integer(parms, 1);
-        string notecard_name = llList2String(parms, 2);
-//log_it("got signature " + signature + " and respcode " + (string)response_code);
-//holding:        if (!current_response_code) {
-            // go ahead and process this request; we aren't busy.
-            reset_for_reading(signature, response_code);
-            global_notecard_name = notecard_name;  // set our global.
-            select_specific_notecard();
-//holding:        } else {
-//holding:            // we're already busy.
-//holding://            send_reply_and_reset(LINK_THIS, [ BUSY_READING_INDICATOR, response_code ],
-//holding://                READ_NOTECARD_COMMAND, FALSE);
-//holding:            // stack this request; another is in progress.
-//holding:            pending_signatures += signature;
-//holding:            pending_response_codes += response_code;
-//holding:            pending_notecard_names += notecard_name;
-//holding:        }
-    }
-}
-
-
-///////////////
-
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, (string)debug_num + "- " + to_say);
-}
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.4.
-// distributed under BSD-like license.
-//   partly based on the self-upgrading scripts from markov brodsky and jippen faddoul.
-// the function auto_retire() should be added *inside* a version numbered script that
-// you wish to give the capability of self-upgrading.
-//   this script supports a notation for versions embedded in script names where a 'v'
-// is followed by a number in the form "major.minor", e.g. "grunkle script by ted v8.2".
-// when the containing script is dropped into an object with a different version, the
-// most recent version eats any existing ones.
-//   keep in mind that this code must be *copied* into your script you wish to add
-// auto-retirement capability to.
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// end hufflets.
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        startup_initialize();
-    }
-    
-    state_exit() {
-        llSetTimerEvent(0);
-    }
-    
-    // we don't do anything until we're given a command to read a notecard.
-    link_message(integer which, integer num, string msg, key id) 
-    {
-        if (num != NOTEWORTHY_HUFFWARE_ID) return;  // not for us.
-        handle_link_message(which, num, msg, id);
-    }
-    
-    on_rez(integer parm) { state rerun; }
-    
-    timer() {
-        llSetTimerEvent(0.0);  // stop any timer now.
-        // let the caller know this has failed out.
-//        if (DEBUGGING) log_it("time out processing '" + requested_signature + "'");
-        send_reply_and_reset(LINK_THIS, [ BAD_NOTECARD_INDICATOR, current_response_code ],
-            READ_NOTECARD_COMMAND, FALSE);
-        current_response_code = 0;  // we gave up on that one.
-        dequeue_next_request();  // get next reading started if we have anything to read.
-    }
-
-    dataserver(key query_id, string data) {
-        // make sure this data is for us.
-        if (global_query_id != query_id) return;
-        // yep, seems to be.
-        process_notecard_line(query_id, data);
-    }
-}
-
-
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/particle_projector_v3.1.lsl b/huffware/huffotronic_updater_freebie_v5.3/particle_projector_v3.1.lsl
new file mode 100755 (executable)
index 0000000..f3201ee
--- /dev/null
@@ -0,0 +1,210 @@
+
+// huffware script: particle projector, by fred huffhines.
+//
+// takes a texture from one side of the object and projects it in a forward X and upward Z direction.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants that can be modified for different behavior.
+float TEXTURE_DISPLAY_LIFE_SPAN = 14.0;  // how long the texture should be shown.
+
+integer SIDE_TO_ACQUIRE_TEXTURE_FROM = 1;  // which side of the object should give us our display texture?
+
+float MAGNIFIER = 4.0;  // how much to expand the texture as it runs.
+
+vector TEXTURE_ACCELERATION = <0.02, 0.0, 0.01>;  // change in speed of the texture over time.
+
+// global variables used in the script.
+
+string texture_to_display = "95c7bb7c-d777-26b1-4052-acd778bfcb40";  // a simple default texture.
+
+// displays a particle system with a texture that gradually enlarges over the object.
+texture_hallucination()
+{
+    // get a bounding box around the object.
+    list bounds = llGetBoundingBox(llGetKey());
+    // calculate the size of the object, which will be our starting particle size.
+    vector size = (vector)llList2String(bounds, 1) - (vector)llList2String(bounds, 0);
+    float chosen_dimension = size.x;
+    if (size.y > chosen_dimension) chosen_dimension = size.y;
+    if (size.z > chosen_dimension) chosen_dimension = size.z;
+    llParticleSystem([
+        // properties regarding the generated particles.
+        PSYS_PART_FLAGS, PSYS_PART_BOUNCE_MASK | PSYS_PART_INTERP_SCALE_MASK,
+        PSYS_PART_START_SCALE, <chosen_dimension, chosen_dimension, 0.0>,
+        PSYS_PART_END_SCALE, <chosen_dimension * MAGNIFIER, chosen_dimension * MAGNIFIER, 0.0>,
+        PSYS_PART_MAX_AGE, TEXTURE_DISPLAY_LIFE_SPAN,
+        PSYS_PART_START_COLOR, <1.0, 1.0, 1.0>,
+        PSYS_PART_END_COLOR, <1.0, 1.0, 1.0>,
+        PSYS_PART_START_ALPHA, 1.0,
+        PSYS_PART_END_ALPHA, 1.0,
+        // properties for the particle system's source.
+        PSYS_SRC_MAX_AGE, TEXTURE_DISPLAY_LIFE_SPAN,
+        PSYS_SRC_TEXTURE, texture_to_display,
+        PSYS_SRC_ACCEL, TEXTURE_ACCELERATION,
+        PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_DROP,
+        PSYS_SRC_BURST_PART_COUNT, 1,
+        PSYS_SRC_BURST_RADIUS, chosen_dimension,
+        PSYS_SRC_BURST_RATE, TEXTURE_DISPLAY_LIFE_SPAN,
+        PSYS_SRC_BURST_SPEED_MIN, 0.01,
+        PSYS_SRC_BURST_SPEED_MAX, 0.01,
+        PSYS_SRC_ANGLE_BEGIN, 0.0,
+        PSYS_SRC_ANGLE_END, 0.0,
+        PSYS_SRC_OMEGA, <0.0, 0.0, 0.0>
+    ]);
+}
+
+// from hufflets...
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default {
+    state_entry() {
+        auto_retire();
+    }
+
+    touch_start(integer touch_count) {
+        integer count = llGetInventoryNumber(INVENTORY_TEXTURE);
+        if (count > 0) {
+            // try getting a texture out of inventory.
+            integer which_texture = llRound(randomize_within_range(0, count - 1, FALSE));
+            texture_to_display = llGetInventoryName(INVENTORY_TEXTURE, which_texture);
+//if (texture_to_display == "") llOwnerSay("fail!  got bad index from random.");
+        } else {
+            // if none in inventory, load the texture to show from our side.
+            texture_to_display = llGetTexture(SIDE_TO_ACQUIRE_TEXTURE_FROM);
+        }
+//llOwnerSay("texture is now: " + texture_to_display);
+        texture_hallucination();
+        llSetTimerEvent(TEXTURE_DISPLAY_LIFE_SPAN + 0.1);
+    }
+
+    timer() {
+        llParticleSystem([]);  // zap it back out again.
+        llSetTimerEvent(0);  // turn off timer.
+    }
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/particle_projector_v3.1.txt b/huffware/huffotronic_updater_freebie_v5.3/particle_projector_v3.1.txt
deleted file mode 100755 (executable)
index f3201ee..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-
-// huffware script: particle projector, by fred huffhines.
-//
-// takes a texture from one side of the object and projects it in a forward X and upward Z direction.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants that can be modified for different behavior.
-float TEXTURE_DISPLAY_LIFE_SPAN = 14.0;  // how long the texture should be shown.
-
-integer SIDE_TO_ACQUIRE_TEXTURE_FROM = 1;  // which side of the object should give us our display texture?
-
-float MAGNIFIER = 4.0;  // how much to expand the texture as it runs.
-
-vector TEXTURE_ACCELERATION = <0.02, 0.0, 0.01>;  // change in speed of the texture over time.
-
-// global variables used in the script.
-
-string texture_to_display = "95c7bb7c-d777-26b1-4052-acd778bfcb40";  // a simple default texture.
-
-// displays a particle system with a texture that gradually enlarges over the object.
-texture_hallucination()
-{
-    // get a bounding box around the object.
-    list bounds = llGetBoundingBox(llGetKey());
-    // calculate the size of the object, which will be our starting particle size.
-    vector size = (vector)llList2String(bounds, 1) - (vector)llList2String(bounds, 0);
-    float chosen_dimension = size.x;
-    if (size.y > chosen_dimension) chosen_dimension = size.y;
-    if (size.z > chosen_dimension) chosen_dimension = size.z;
-    llParticleSystem([
-        // properties regarding the generated particles.
-        PSYS_PART_FLAGS, PSYS_PART_BOUNCE_MASK | PSYS_PART_INTERP_SCALE_MASK,
-        PSYS_PART_START_SCALE, <chosen_dimension, chosen_dimension, 0.0>,
-        PSYS_PART_END_SCALE, <chosen_dimension * MAGNIFIER, chosen_dimension * MAGNIFIER, 0.0>,
-        PSYS_PART_MAX_AGE, TEXTURE_DISPLAY_LIFE_SPAN,
-        PSYS_PART_START_COLOR, <1.0, 1.0, 1.0>,
-        PSYS_PART_END_COLOR, <1.0, 1.0, 1.0>,
-        PSYS_PART_START_ALPHA, 1.0,
-        PSYS_PART_END_ALPHA, 1.0,
-        // properties for the particle system's source.
-        PSYS_SRC_MAX_AGE, TEXTURE_DISPLAY_LIFE_SPAN,
-        PSYS_SRC_TEXTURE, texture_to_display,
-        PSYS_SRC_ACCEL, TEXTURE_ACCELERATION,
-        PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_DROP,
-        PSYS_SRC_BURST_PART_COUNT, 1,
-        PSYS_SRC_BURST_RADIUS, chosen_dimension,
-        PSYS_SRC_BURST_RATE, TEXTURE_DISPLAY_LIFE_SPAN,
-        PSYS_SRC_BURST_SPEED_MIN, 0.01,
-        PSYS_SRC_BURST_SPEED_MAX, 0.01,
-        PSYS_SRC_ANGLE_BEGIN, 0.0,
-        PSYS_SRC_ANGLE_END, 0.0,
-        PSYS_SRC_OMEGA, <0.0, 0.0, 0.0>
-    ]);
-}
-
-// from hufflets...
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default {
-    state_entry() {
-        auto_retire();
-    }
-
-    touch_start(integer touch_count) {
-        integer count = llGetInventoryNumber(INVENTORY_TEXTURE);
-        if (count > 0) {
-            // try getting a texture out of inventory.
-            integer which_texture = llRound(randomize_within_range(0, count - 1, FALSE));
-            texture_to_display = llGetInventoryName(INVENTORY_TEXTURE, which_texture);
-//if (texture_to_display == "") llOwnerSay("fail!  got bad index from random.");
-        } else {
-            // if none in inventory, load the texture to show from our side.
-            texture_to_display = llGetTexture(SIDE_TO_ACQUIRE_TEXTURE_FROM);
-        }
-//llOwnerSay("texture is now: " + texture_to_display);
-        texture_hallucination();
-        llSetTimerEvent(TEXTURE_DISPLAY_LIFE_SPAN + 0.1);
-    }
-
-    timer() {
-        llParticleSystem([]);  // zap it back out again.
-        llSetTimerEvent(0);  // turn off timer.
-    }
-}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/party_culiar_v5.7.lsl b/huffware/huffotronic_updater_freebie_v5.3/party_culiar_v5.7.lsl
new file mode 100755 (executable)
index 0000000..ed0382a
--- /dev/null
@@ -0,0 +1,646 @@
+
+// huffware script: "party culiar", by fred huffhines
+//
+// this is yet another particle system script, based on ideas seen
+// in several scripts by various authors and assisted by the lsl wiki.
+// it has the useful characteristic of being able to load its parameters
+// from a notecard, thus making script modifications for the particle
+// system unnecessary.  
+// on initial rez, if a notecard exists, then it is read for particle
+// system parameters named similarly to the variables below (see the
+// particle archetype notecard for more details).  if the object is
+// rezzed with an existing particle system already read from a notecard
+// that's still present, it will keep playing that particle system.
+// if a notecard is added or changed, then the particle variables are
+// read again.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// party culiar link message API.
+//////////////
+integer PARTYCULIAR_HUFFWARE_ID = 10018;
+    // a unique ID within the huffware system for this script.
+string HUFFWARE_PARM_SEPARATOR = "~~~";
+    // three tildes is an uncommon thing to have otherwise, so we use it to separate
+    // our commands in linked messages.
+//
+string PARTYCULIAR_POWER_COMMAND = "#powrpcl";
+    // tells the particle system to either turn on or off.  the single parameter is
+    // either "on", "1", "true", or "off", "0", "false".
+//////////////
+
+// constants...
+float MIN_ROTATION = 0.1;  // rotations used for omega value to rotate particles.
+float MAX_ROTATION = 4.0;
+
+// items controlled by the notecard...
+
+// noisiness...
+integer debug = FALSE;  // controls whether logging occurs.
+
+integer start_enabled = FALSE;  // if true, particle system starts up right away.
+
+// color...
+integer interpolate_colors = TRUE;
+integer randomize_colors = FALSE;
+vector starting_color = <0.5, 0.7, 0.9>;
+vector ending_color = <0.0, 1.0, 0.3>;
+
+// particle size...
+integer interpolate_size = TRUE;
+vector final_dimensions = <1.8, 1.8, 1.8>;
+vector initial_dimensions = <0.72, 0.72, 0.72>;
+
+// transparency...
+//   1.0 means completely opaque and 0.0 means completely transparent.
+float initial_opacity = 1.0;
+float final_opacity = 0.3;
+
+// target following (or not)...
+integer follow_target_key = FALSE;
+key target_key = NULL_KEY;
+
+// speed and acceleration of particles...
+float minimum_velocity = 0.4;
+float maximum_velocity = 1.4;
+vector acceleration = <0.0, 0.4, 0.7>;
+integer wind_blown = TRUE;  // are particles affected by wind?
+
+// freaky effects for particles...
+integer bounce_off_z_height = FALSE;  // start at height of containing object.
+integer glowing = FALSE;  // particles will glow.
+integer source_centered = TRUE;  // particles start at object's center.
+integer point_toward_velocity = TRUE;  // rotate vertical axis toward velocity.
+
+string particle_texture = "";  // image used for the particle, if any.
+
+// when randomizing colors, these control how long a choice lasts.
+float minimum_hold_time = 5.0;
+float maximum_hold_time = 20.0;
+
+// timing (in seconds)...
+float lifespan_for_particle = 3.0;
+float lifespan_for_system = 0.0;  // 0 means unlimited.
+float creation_rate = 0.2;  // delay between particle creations.
+integer siblings = 7;  // how many to create at once.
+
+// how to exude particles.
+integer emission_pattern
+    = PSYS_SRC_PATTERN_ANGLE;  // 2D emission between given angles.
+    // = PSYS_SRC_PATTERN_DROP;  // just plop them at center of object.
+    // = PSYS_SRC_PATTERN_EXPLODE;  // spew them out as if exploded.
+    // = PSYS_SRC_PATTERN_ANGLE_CONE;  // 3D emission between given angles.
+    // = PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY;  // inverse of angle cone.
+
+// pattern details...
+float starting_angle = 1.0;  // initial angle where particles are emitted.
+float ending_angle = 0.0;  // bounding angle for emission.
+vector rotation_between_bursts = <0.2, 0.2, 0.2>;  // used in angle patterns.
+float burst_radius = 2.0;  // emission distance from source, unused for source centered.
+
+// add-in...  huffware script: notecard library, by fred huffhines
+
+string current_notecard_name;  // the name of the card we're reading now.
+key current_query_id;  // the query ID for the current notecard.
+list query_contents;  // the lines we have read from the notecard.
+integer line_number;  // which line are we at in notecard?
+
+initialize()
+{
+    current_notecard_name = "";
+    current_query_id = NULL_KEY;
+    query_contents = [];
+    line_number = 0;
+}
+
+string dump_list(list to_show)
+{
+    integer len = llGetListLength(to_show);
+    integer i;
+    string text;
+    for (i = len - 1; i >= 0; i--) {
+        text += llList2String(to_show, i) + "\n";
+    }
+    return text;
+}
+
+//////////////
+
+create_particle_system()
+{
+    if (randomize_colors) {
+        starting_color = <randomize_within_range(0.28, 0.95, FALSE),
+            randomize_within_range(0.28, 0.95, FALSE),
+            randomize_within_range(0.28, 0.95, FALSE)>;
+        ending_color = <randomize_within_range(0.14, 0.85, FALSE),
+            randomize_within_range(0.14, 0.85, FALSE),
+            randomize_within_range(0.14, 0.85, FALSE)>;
+    }
+    
+    list system_parameters;
+    integer flags_for_particle_effects = 0;
+
+    if (interpolate_colors)
+        flags_for_particle_effects = PSYS_PART_INTERP_COLOR_MASK | flags_for_particle_effects;
+    system_parameters += [ PSYS_PART_START_COLOR, starting_color,
+        PSYS_PART_END_COLOR, ending_color ];    
+
+    if (interpolate_size)
+        flags_for_particle_effects = PSYS_PART_INTERP_SCALE_MASK | flags_for_particle_effects;
+    system_parameters += [ PSYS_PART_START_SCALE, initial_dimensions,
+        PSYS_PART_END_SCALE, final_dimensions ];
+
+    system_parameters += [ PSYS_PART_START_ALPHA, initial_opacity,
+        PSYS_PART_END_ALPHA, final_opacity ];
+
+    if (follow_target_key && (target_key != NULL_KEY) ) {
+        flags_for_particle_effects = PSYS_PART_TARGET_POS_MASK | flags_for_particle_effects;
+        system_parameters += [ PSYS_SRC_TARGET_KEY, target_key ];
+    }
+
+    system_parameters += [ PSYS_SRC_BURST_SPEED_MIN, minimum_velocity,
+        PSYS_SRC_BURST_SPEED_MAX, maximum_velocity,
+        PSYS_SRC_ACCEL, acceleration ];
+    if (wind_blown)
+        flags_for_particle_effects = PSYS_PART_WIND_MASK | flags_for_particle_effects;
+
+    if (particle_texture != "")
+        system_parameters += [ PSYS_SRC_TEXTURE, particle_texture ];
+
+    if (emission_pattern != 0)
+        system_parameters += [ PSYS_SRC_PATTERN, emission_pattern ];
+
+    system_parameters += [ PSYS_PART_MAX_AGE, lifespan_for_particle,
+        PSYS_SRC_MAX_AGE, lifespan_for_system,
+        PSYS_SRC_BURST_PART_COUNT, siblings,
+        PSYS_SRC_BURST_RATE, creation_rate ];
+
+//hmmm: only add if used?
+    system_parameters += [ PSYS_SRC_ANGLE_BEGIN, starting_angle,
+        PSYS_SRC_ANGLE_END, ending_angle,
+        PSYS_SRC_OMEGA, rotation_between_bursts ];
+        
+    // assorted effects...
+    if (bounce_off_z_height)
+        flags_for_particle_effects = PSYS_PART_BOUNCE_MASK | flags_for_particle_effects;
+    if (glowing)
+        flags_for_particle_effects = PSYS_PART_EMISSIVE_MASK | flags_for_particle_effects;
+    if (point_toward_velocity)
+        flags_for_particle_effects = PSYS_PART_FOLLOW_VELOCITY_MASK | flags_for_particle_effects;
+    if (source_centered)
+        flags_for_particle_effects = PSYS_PART_FOLLOW_SRC_MASK | flags_for_particle_effects;
+    else
+        system_parameters += [ PSYS_SRC_BURST_RADIUS, burst_radius ];  // okay to use.
+
+    // now that we're done accumulating the flags, we can add them to our list.
+    system_parameters += [ PSYS_PART_FLAGS, flags_for_particle_effects ];  // must be last.
+
+    // and finally, we are ready to create the particle system of our dreams...    
+    llParticleSystem(system_parameters);
+}
+
+// returns a non-empty string if "to_check" defines contents for "variable_name".
+string defines_variable(string to_check, string variable_name)
+{
+    // clean initial spaces.
+    while (llGetSubString(to_check, 0, 0) == " ")
+        to_check = llDeleteSubString(to_check, 0, 0);
+    if (!is_prefix(to_check, variable_name)) return "";
+    to_check = llDeleteSubString(to_check, 0, llStringLength(variable_name) - 1);
+    // clean any spaces or valid assignment characters.
+    while ( (llGetSubString(to_check, 0, 0) == " ")
+            || (llGetSubString(to_check, 0, 0) == "=")
+            || (llGetSubString(to_check, 0, 0) == ",") )
+        to_check = llDeleteSubString(to_check, 0, 0);
+    if (debug)
+        log_it("set " + variable_name + " = " + to_check);    
+    // return what's left of the string.
+    return to_check;
+}
+
+parse_variable_definition(string to_parse)
+{
+    string content;  // filled after finding a variable name.
+    string texture_name;  // temporary used in reading texture name.
+    
+    if ( (content = defines_variable(to_parse, "debug")) != "")
+        debug = (integer)content;
+    else if ( (content = defines_variable(to_parse, "interpolate_colors")) != "")
+        interpolate_colors = (integer)content;
+    else if ( (content = defines_variable(to_parse, "randomize_colors")) != "")
+        randomize_colors = (integer)content;
+    else if ( (content = defines_variable(to_parse, "starting_color")) != "")
+        starting_color = (vector)content;
+    else if ( (content = defines_variable(to_parse, "ending_color")) != "")
+        ending_color = (vector)content;
+    else if ( (content = defines_variable(to_parse, "interpolate_size")) != "")
+        interpolate_size = (integer)content;
+    else if ( (content = defines_variable(to_parse, "initial_dimensions")) != "")
+        initial_dimensions = (vector)content;
+    else if ( (content = defines_variable(to_parse, "final_dimensions")) != "")
+        final_dimensions = (vector)content;
+    else if ( (content = defines_variable(to_parse, "initial_opacity")) != "")
+        initial_opacity = (float)content;
+    else if ( (content = defines_variable(to_parse, "final_opacity")) != "")
+        final_opacity = (float)content;
+    else if ( (content = defines_variable(to_parse, "follow_target_key")) != "")
+        follow_target_key = (integer)content;
+    else if ( (content = defines_variable(to_parse, "target_key")) != "")
+        target_key = (string)content;
+    else if ( (content = defines_variable(to_parse, "minimum_velocity")) != "")
+        minimum_velocity = (float)content;
+    else if ( (content = defines_variable(to_parse, "maximum_velocity")) != "")
+        maximum_velocity = (float)content;
+    else if ( (content = defines_variable(to_parse, "wind_blown")) != "")
+        wind_blown = (integer)content;
+    else if ( (content = defines_variable(to_parse, "acceleration")) != "")
+        acceleration = (vector)content;
+    else if ( (content = defines_variable(to_parse, "bounce_off_z_height")) != "")
+        bounce_off_z_height = (integer)content;
+    else if ( (content = defines_variable(to_parse, "glowing")) != "")
+        glowing = (integer)content;
+    else if ( (content = defines_variable(to_parse, "source_centered")) != "")
+        source_centered = (integer)content;
+    else if ( (content = defines_variable(to_parse, "point_toward_velocity")) != "")
+        point_toward_velocity = (integer)content;
+    else if ( (content = defines_variable(to_parse, "particle_texture")) != "")
+        particle_texture = (string)content;
+    else if ( (content = defines_variable(to_parse, "lifespan_for_particle")) != "")
+        lifespan_for_particle = (float)content;
+    else if ( (content = defines_variable(to_parse, "lifespan_for_system")) != "")
+        lifespan_for_system = (float)content;
+    else if ( (content = defines_variable(to_parse, "creation_rate")) != "")
+        creation_rate = (float)content;
+    else if ( (content = defines_variable(to_parse, "siblings")) != "")
+        siblings = (integer)content;
+    else if ( (content = defines_variable(to_parse, "minimum_hold_time")) != "")
+        minimum_hold_time = (float)content;
+    else if ( (content = defines_variable(to_parse, "maximum_hold_time")) != "")
+        maximum_hold_time = (float)content;
+    else if ( (content = defines_variable(to_parse, "emission_pattern")) != "") {
+        texture_name = (string)content;
+        // translate the short hand name into an emission_pattern value.
+        if (texture_name == "ANGLE") emission_pattern = PSYS_SRC_PATTERN_ANGLE;
+        else if (texture_name == "DROP") emission_pattern = PSYS_SRC_PATTERN_DROP;
+        else if (texture_name == "EXPLODE") emission_pattern = PSYS_SRC_PATTERN_EXPLODE;
+        else if (texture_name == "ANGLE_CONE") emission_pattern = PSYS_SRC_PATTERN_ANGLE_CONE;
+        else if (texture_name == "ANGLE_CONE_EMPTY")
+            emission_pattern = PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY;
+//log_it("emission pattern is now " + (string)emission_pattern);
+    }
+    else if ( (content = defines_variable(to_parse, "starting_angle")) != "")
+        starting_angle = (float)content;
+    else if ( (content = defines_variable(to_parse, "ending_angle")) != "")
+        ending_angle = (float)content;
+    else if ( (content = defines_variable(to_parse, "rotation_between_bursts")) != "") {
+        if (content == "random")
+            rotation_between_bursts = <randomize_within_range(MIN_ROTATION, MAX_ROTATION, TRUE),
+                randomize_within_range(MIN_ROTATION, MAX_ROTATION, TRUE),
+                randomize_within_range(MIN_ROTATION, MAX_ROTATION, TRUE)>;
+        else
+            rotation_between_bursts = (vector)content;
+    } else if ( (content = defines_variable(to_parse, "burst_radius")) != "")
+        burst_radius = (float)content;
+    else if ( (content = defines_variable(to_parse, "running")) != "")
+        start_enabled = (integer)content;
+
+    // special cases for key to follow...
+    if (target_key == "owner") target_key = llGetOwner();
+    else if (target_key == "self") target_key = llGetKey();
+    // special cases for texture.
+    if (particle_texture == "inventory")
+        particle_texture = llGetInventoryName(INVENTORY_TEXTURE, 0);
+
+}
+
+process_particle_settings(list particle_definitions)
+{
+    integer current_item = 0;
+    integer max_items = llGetListLength(particle_definitions);
+    while (current_item < max_items) {
+        string curr_line = llList2String(particle_definitions, current_item);
+        parse_variable_definition(curr_line);
+        current_item++;
+    }
+}
+
+randomize_timer()
+{
+    if (randomize_colors) {
+        llSetTimerEvent(randomize_within_range(maximum_hold_time,
+            minimum_hold_time, FALSE));
+    }
+}
+
+stop_timer() { llSetTimerEvent(0.0); }
+
+check_for_notecard()
+{
+    if (current_notecard_name != "") return;
+    // if there's a notecard, then we will start reading it.
+    if (llGetInventoryNumber(INVENTORY_NOTECARD) > 0) {
+        current_notecard_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
+        line_number = 0;
+        query_contents = [];
+        current_query_id = llGetNotecardLine(current_notecard_name, 0);
+        llSetTimerEvent(80);
+    }
+}
+
+// this should be invoked from the link_message event handler to process the requests
+// for whatever service this library script provides.
+handle_link_message(integer sender, integer huff_id, string msg, key id)
+{
+    if (huff_id != PARTYCULIAR_HUFFWARE_ID) {
+        return;
+    }
+//llOwnerSay("link msg: " + (string)sender + " " + (string)huff_id + " msg=" + msg + " id=" + (string)id);
+    if (msg == PARTYCULIAR_POWER_COMMAND) {
+        string cmd = id;
+        if ( (find_substring(id, "on") == 0)
+            || (find_substring(id, "1") == 0)
+            || (find_substring(id, "true") == 0) ) {
+            // they want to crank the particle system up.
+            create_particle_system();
+            randomize_timer();
+        } else if ( (find_substring(id, "off") == 0)
+            || (find_substring(id, "0") == 0)
+            || (find_substring(id, "false") == 0) ) {
+            // the request is to shut the party down now.
+            llParticleSystem([]);
+            stop_timer();
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+//////////////
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat, but use an unusual channel.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+}
+
+//////////////
+
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+
+// handles when blank strings need to come through the pipe.
+string wrap_blank_string(string to_wrap)
+{
+    if (llStringLength(to_wrap)) return to_wrap;  // that one is okay.
+    return "\"\"";  // return a quoted nothing as a signal for a blank.
+}
+
+// undoes a previously wrapped blank string.
+string interpret_blank_string(string to_unwrap)
+{
+    if (to_unwrap == "\"\"") return "";  // that was an encoded blank.
+    return to_unwrap;  // no encoding.
+}
+
+// a simple version of a reply for a command that has been executed.  the parameters
+// might contain an outcome or result of the operation that was requested.
+send_reply(integer destination, list parms, string command)
+{
+    llMessageLinked(destination, PARTYCULIAR_HUFFWARE_ID, command,
+        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
+}
+
+//////////////
+
+// returns a number at most maximum and at least minimum.
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// the string processing methods are not case sensitive.
+  
+// returns TRUE if the "pattern" is found in the "full_string".
+integer matches_substring(string full_string, string pattern)
+{ return (find_substring(full_string, pattern) >= 0); }
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return find_substring(compare_with, prefix) == 0; }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        initialize();
+        if (start_enabled) {
+            create_particle_system();
+            randomize_timer();
+        } else {
+            llParticleSystem([]);
+            stop_timer();
+        }
+        check_for_notecard();
+    }
+    
+    timer() {
+        if (current_query_id != NULL_KEY) {
+            // there's been a failure of some sort; we were supposed to get a notecard to read.
+            llWhisper(0, "Failed to read the notecard, now restarting.");
+            llResetScript();
+        }
+        create_particle_system();
+        randomize_timer();
+    }
+    
+    on_rez(integer parm) {
+        target_key = llGetKey();  // reset to get rid of weird wrong keys.
+        llResetScript();
+    }
+
+    link_message(integer sender, integer num, string msg, key id) {
+        handle_link_message(sender, num, msg, id);
+    }
+
+    changed(integer change_type) {
+        if (change_type != CHANGED_INVENTORY) {
+            // we only care about inventory changes here.
+            return;
+        }
+        llResetScript();
+    }
+    
+    dataserver(key query_id, string data) {
+        if (query_id != current_query_id) {
+log_it("not our query id somehow?  weird query had: id=" + (string)query_id + " data=" + (string)data);
+            // to heck with all this weirdness; if there's a failure, start over.
+            llResetScript();
+        }
+        // if we're not at the end of the notecard we're reading...
+        if (data != EOF) {
+            if (!line_number) {
+                if (data != "#party culiar") {
+                    // this card has the wrong signature at the top.  quit bothering
+                    // with it now.
+                    return;
+                }
+                log_it("starting to read notecard " + current_notecard_name + "...");    
+            }
+            if (data != "") {
+                 // add the non-blank line to our destination list.
+                query_contents += data;
+//log_it("line " + (string)line_number + ": data=" + data);
+            }
+            line_number++;  // increase the line count.
+            // request the next line from the notecard.
+            current_query_id = llGetNotecardLine(current_notecard_name, line_number);
+        } else {
+            // no more data, so we're done with this card.
+            current_query_id = NULL_KEY;
+            if (!llGetListLength(query_contents)) {
+                // nothing was read?  the heck with this card.
+                current_notecard_name = "";  // toss bad card.
+                return;
+            }
+//log_it("notecard said:\n" + dump_list(query_contents));
+            process_particle_settings(query_contents);
+            if (start_enabled) {
+                create_particle_system();
+                randomize_timer();
+            } else {
+                llParticleSystem([]);
+                stop_timer();
+            }
+            log_it("done reading notecard " + current_notecard_name + ".");
+        }
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/party_culiar_v5.7.txt b/huffware/huffotronic_updater_freebie_v5.3/party_culiar_v5.7.txt
deleted file mode 100755 (executable)
index ed0382a..0000000
+++ /dev/null
@@ -1,646 +0,0 @@
-
-// huffware script: "party culiar", by fred huffhines
-//
-// this is yet another particle system script, based on ideas seen
-// in several scripts by various authors and assisted by the lsl wiki.
-// it has the useful characteristic of being able to load its parameters
-// from a notecard, thus making script modifications for the particle
-// system unnecessary.  
-// on initial rez, if a notecard exists, then it is read for particle
-// system parameters named similarly to the variables below (see the
-// particle archetype notecard for more details).  if the object is
-// rezzed with an existing particle system already read from a notecard
-// that's still present, it will keep playing that particle system.
-// if a notecard is added or changed, then the particle variables are
-// read again.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// party culiar link message API.
-//////////////
-integer PARTYCULIAR_HUFFWARE_ID = 10018;
-    // a unique ID within the huffware system for this script.
-string HUFFWARE_PARM_SEPARATOR = "~~~";
-    // three tildes is an uncommon thing to have otherwise, so we use it to separate
-    // our commands in linked messages.
-//
-string PARTYCULIAR_POWER_COMMAND = "#powrpcl";
-    // tells the particle system to either turn on or off.  the single parameter is
-    // either "on", "1", "true", or "off", "0", "false".
-//////////////
-
-// constants...
-float MIN_ROTATION = 0.1;  // rotations used for omega value to rotate particles.
-float MAX_ROTATION = 4.0;
-
-// items controlled by the notecard...
-
-// noisiness...
-integer debug = FALSE;  // controls whether logging occurs.
-
-integer start_enabled = FALSE;  // if true, particle system starts up right away.
-
-// color...
-integer interpolate_colors = TRUE;
-integer randomize_colors = FALSE;
-vector starting_color = <0.5, 0.7, 0.9>;
-vector ending_color = <0.0, 1.0, 0.3>;
-
-// particle size...
-integer interpolate_size = TRUE;
-vector final_dimensions = <1.8, 1.8, 1.8>;
-vector initial_dimensions = <0.72, 0.72, 0.72>;
-
-// transparency...
-//   1.0 means completely opaque and 0.0 means completely transparent.
-float initial_opacity = 1.0;
-float final_opacity = 0.3;
-
-// target following (or not)...
-integer follow_target_key = FALSE;
-key target_key = NULL_KEY;
-
-// speed and acceleration of particles...
-float minimum_velocity = 0.4;
-float maximum_velocity = 1.4;
-vector acceleration = <0.0, 0.4, 0.7>;
-integer wind_blown = TRUE;  // are particles affected by wind?
-
-// freaky effects for particles...
-integer bounce_off_z_height = FALSE;  // start at height of containing object.
-integer glowing = FALSE;  // particles will glow.
-integer source_centered = TRUE;  // particles start at object's center.
-integer point_toward_velocity = TRUE;  // rotate vertical axis toward velocity.
-
-string particle_texture = "";  // image used for the particle, if any.
-
-// when randomizing colors, these control how long a choice lasts.
-float minimum_hold_time = 5.0;
-float maximum_hold_time = 20.0;
-
-// timing (in seconds)...
-float lifespan_for_particle = 3.0;
-float lifespan_for_system = 0.0;  // 0 means unlimited.
-float creation_rate = 0.2;  // delay between particle creations.
-integer siblings = 7;  // how many to create at once.
-
-// how to exude particles.
-integer emission_pattern
-    = PSYS_SRC_PATTERN_ANGLE;  // 2D emission between given angles.
-    // = PSYS_SRC_PATTERN_DROP;  // just plop them at center of object.
-    // = PSYS_SRC_PATTERN_EXPLODE;  // spew them out as if exploded.
-    // = PSYS_SRC_PATTERN_ANGLE_CONE;  // 3D emission between given angles.
-    // = PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY;  // inverse of angle cone.
-
-// pattern details...
-float starting_angle = 1.0;  // initial angle where particles are emitted.
-float ending_angle = 0.0;  // bounding angle for emission.
-vector rotation_between_bursts = <0.2, 0.2, 0.2>;  // used in angle patterns.
-float burst_radius = 2.0;  // emission distance from source, unused for source centered.
-
-// add-in...  huffware script: notecard library, by fred huffhines
-
-string current_notecard_name;  // the name of the card we're reading now.
-key current_query_id;  // the query ID for the current notecard.
-list query_contents;  // the lines we have read from the notecard.
-integer line_number;  // which line are we at in notecard?
-
-initialize()
-{
-    current_notecard_name = "";
-    current_query_id = NULL_KEY;
-    query_contents = [];
-    line_number = 0;
-}
-
-string dump_list(list to_show)
-{
-    integer len = llGetListLength(to_show);
-    integer i;
-    string text;
-    for (i = len - 1; i >= 0; i--) {
-        text += llList2String(to_show, i) + "\n";
-    }
-    return text;
-}
-
-//////////////
-
-create_particle_system()
-{
-    if (randomize_colors) {
-        starting_color = <randomize_within_range(0.28, 0.95, FALSE),
-            randomize_within_range(0.28, 0.95, FALSE),
-            randomize_within_range(0.28, 0.95, FALSE)>;
-        ending_color = <randomize_within_range(0.14, 0.85, FALSE),
-            randomize_within_range(0.14, 0.85, FALSE),
-            randomize_within_range(0.14, 0.85, FALSE)>;
-    }
-    
-    list system_parameters;
-    integer flags_for_particle_effects = 0;
-
-    if (interpolate_colors)
-        flags_for_particle_effects = PSYS_PART_INTERP_COLOR_MASK | flags_for_particle_effects;
-    system_parameters += [ PSYS_PART_START_COLOR, starting_color,
-        PSYS_PART_END_COLOR, ending_color ];    
-
-    if (interpolate_size)
-        flags_for_particle_effects = PSYS_PART_INTERP_SCALE_MASK | flags_for_particle_effects;
-    system_parameters += [ PSYS_PART_START_SCALE, initial_dimensions,
-        PSYS_PART_END_SCALE, final_dimensions ];
-
-    system_parameters += [ PSYS_PART_START_ALPHA, initial_opacity,
-        PSYS_PART_END_ALPHA, final_opacity ];
-
-    if (follow_target_key && (target_key != NULL_KEY) ) {
-        flags_for_particle_effects = PSYS_PART_TARGET_POS_MASK | flags_for_particle_effects;
-        system_parameters += [ PSYS_SRC_TARGET_KEY, target_key ];
-    }
-
-    system_parameters += [ PSYS_SRC_BURST_SPEED_MIN, minimum_velocity,
-        PSYS_SRC_BURST_SPEED_MAX, maximum_velocity,
-        PSYS_SRC_ACCEL, acceleration ];
-    if (wind_blown)
-        flags_for_particle_effects = PSYS_PART_WIND_MASK | flags_for_particle_effects;
-
-    if (particle_texture != "")
-        system_parameters += [ PSYS_SRC_TEXTURE, particle_texture ];
-
-    if (emission_pattern != 0)
-        system_parameters += [ PSYS_SRC_PATTERN, emission_pattern ];
-
-    system_parameters += [ PSYS_PART_MAX_AGE, lifespan_for_particle,
-        PSYS_SRC_MAX_AGE, lifespan_for_system,
-        PSYS_SRC_BURST_PART_COUNT, siblings,
-        PSYS_SRC_BURST_RATE, creation_rate ];
-
-//hmmm: only add if used?
-    system_parameters += [ PSYS_SRC_ANGLE_BEGIN, starting_angle,
-        PSYS_SRC_ANGLE_END, ending_angle,
-        PSYS_SRC_OMEGA, rotation_between_bursts ];
-        
-    // assorted effects...
-    if (bounce_off_z_height)
-        flags_for_particle_effects = PSYS_PART_BOUNCE_MASK | flags_for_particle_effects;
-    if (glowing)
-        flags_for_particle_effects = PSYS_PART_EMISSIVE_MASK | flags_for_particle_effects;
-    if (point_toward_velocity)
-        flags_for_particle_effects = PSYS_PART_FOLLOW_VELOCITY_MASK | flags_for_particle_effects;
-    if (source_centered)
-        flags_for_particle_effects = PSYS_PART_FOLLOW_SRC_MASK | flags_for_particle_effects;
-    else
-        system_parameters += [ PSYS_SRC_BURST_RADIUS, burst_radius ];  // okay to use.
-
-    // now that we're done accumulating the flags, we can add them to our list.
-    system_parameters += [ PSYS_PART_FLAGS, flags_for_particle_effects ];  // must be last.
-
-    // and finally, we are ready to create the particle system of our dreams...    
-    llParticleSystem(system_parameters);
-}
-
-// returns a non-empty string if "to_check" defines contents for "variable_name".
-string defines_variable(string to_check, string variable_name)
-{
-    // clean initial spaces.
-    while (llGetSubString(to_check, 0, 0) == " ")
-        to_check = llDeleteSubString(to_check, 0, 0);
-    if (!is_prefix(to_check, variable_name)) return "";
-    to_check = llDeleteSubString(to_check, 0, llStringLength(variable_name) - 1);
-    // clean any spaces or valid assignment characters.
-    while ( (llGetSubString(to_check, 0, 0) == " ")
-            || (llGetSubString(to_check, 0, 0) == "=")
-            || (llGetSubString(to_check, 0, 0) == ",") )
-        to_check = llDeleteSubString(to_check, 0, 0);
-    if (debug)
-        log_it("set " + variable_name + " = " + to_check);    
-    // return what's left of the string.
-    return to_check;
-}
-
-parse_variable_definition(string to_parse)
-{
-    string content;  // filled after finding a variable name.
-    string texture_name;  // temporary used in reading texture name.
-    
-    if ( (content = defines_variable(to_parse, "debug")) != "")
-        debug = (integer)content;
-    else if ( (content = defines_variable(to_parse, "interpolate_colors")) != "")
-        interpolate_colors = (integer)content;
-    else if ( (content = defines_variable(to_parse, "randomize_colors")) != "")
-        randomize_colors = (integer)content;
-    else if ( (content = defines_variable(to_parse, "starting_color")) != "")
-        starting_color = (vector)content;
-    else if ( (content = defines_variable(to_parse, "ending_color")) != "")
-        ending_color = (vector)content;
-    else if ( (content = defines_variable(to_parse, "interpolate_size")) != "")
-        interpolate_size = (integer)content;
-    else if ( (content = defines_variable(to_parse, "initial_dimensions")) != "")
-        initial_dimensions = (vector)content;
-    else if ( (content = defines_variable(to_parse, "final_dimensions")) != "")
-        final_dimensions = (vector)content;
-    else if ( (content = defines_variable(to_parse, "initial_opacity")) != "")
-        initial_opacity = (float)content;
-    else if ( (content = defines_variable(to_parse, "final_opacity")) != "")
-        final_opacity = (float)content;
-    else if ( (content = defines_variable(to_parse, "follow_target_key")) != "")
-        follow_target_key = (integer)content;
-    else if ( (content = defines_variable(to_parse, "target_key")) != "")
-        target_key = (string)content;
-    else if ( (content = defines_variable(to_parse, "minimum_velocity")) != "")
-        minimum_velocity = (float)content;
-    else if ( (content = defines_variable(to_parse, "maximum_velocity")) != "")
-        maximum_velocity = (float)content;
-    else if ( (content = defines_variable(to_parse, "wind_blown")) != "")
-        wind_blown = (integer)content;
-    else if ( (content = defines_variable(to_parse, "acceleration")) != "")
-        acceleration = (vector)content;
-    else if ( (content = defines_variable(to_parse, "bounce_off_z_height")) != "")
-        bounce_off_z_height = (integer)content;
-    else if ( (content = defines_variable(to_parse, "glowing")) != "")
-        glowing = (integer)content;
-    else if ( (content = defines_variable(to_parse, "source_centered")) != "")
-        source_centered = (integer)content;
-    else if ( (content = defines_variable(to_parse, "point_toward_velocity")) != "")
-        point_toward_velocity = (integer)content;
-    else if ( (content = defines_variable(to_parse, "particle_texture")) != "")
-        particle_texture = (string)content;
-    else if ( (content = defines_variable(to_parse, "lifespan_for_particle")) != "")
-        lifespan_for_particle = (float)content;
-    else if ( (content = defines_variable(to_parse, "lifespan_for_system")) != "")
-        lifespan_for_system = (float)content;
-    else if ( (content = defines_variable(to_parse, "creation_rate")) != "")
-        creation_rate = (float)content;
-    else if ( (content = defines_variable(to_parse, "siblings")) != "")
-        siblings = (integer)content;
-    else if ( (content = defines_variable(to_parse, "minimum_hold_time")) != "")
-        minimum_hold_time = (float)content;
-    else if ( (content = defines_variable(to_parse, "maximum_hold_time")) != "")
-        maximum_hold_time = (float)content;
-    else if ( (content = defines_variable(to_parse, "emission_pattern")) != "") {
-        texture_name = (string)content;
-        // translate the short hand name into an emission_pattern value.
-        if (texture_name == "ANGLE") emission_pattern = PSYS_SRC_PATTERN_ANGLE;
-        else if (texture_name == "DROP") emission_pattern = PSYS_SRC_PATTERN_DROP;
-        else if (texture_name == "EXPLODE") emission_pattern = PSYS_SRC_PATTERN_EXPLODE;
-        else if (texture_name == "ANGLE_CONE") emission_pattern = PSYS_SRC_PATTERN_ANGLE_CONE;
-        else if (texture_name == "ANGLE_CONE_EMPTY")
-            emission_pattern = PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY;
-//log_it("emission pattern is now " + (string)emission_pattern);
-    }
-    else if ( (content = defines_variable(to_parse, "starting_angle")) != "")
-        starting_angle = (float)content;
-    else if ( (content = defines_variable(to_parse, "ending_angle")) != "")
-        ending_angle = (float)content;
-    else if ( (content = defines_variable(to_parse, "rotation_between_bursts")) != "") {
-        if (content == "random")
-            rotation_between_bursts = <randomize_within_range(MIN_ROTATION, MAX_ROTATION, TRUE),
-                randomize_within_range(MIN_ROTATION, MAX_ROTATION, TRUE),
-                randomize_within_range(MIN_ROTATION, MAX_ROTATION, TRUE)>;
-        else
-            rotation_between_bursts = (vector)content;
-    } else if ( (content = defines_variable(to_parse, "burst_radius")) != "")
-        burst_radius = (float)content;
-    else if ( (content = defines_variable(to_parse, "running")) != "")
-        start_enabled = (integer)content;
-
-    // special cases for key to follow...
-    if (target_key == "owner") target_key = llGetOwner();
-    else if (target_key == "self") target_key = llGetKey();
-    // special cases for texture.
-    if (particle_texture == "inventory")
-        particle_texture = llGetInventoryName(INVENTORY_TEXTURE, 0);
-
-}
-
-process_particle_settings(list particle_definitions)
-{
-    integer current_item = 0;
-    integer max_items = llGetListLength(particle_definitions);
-    while (current_item < max_items) {
-        string curr_line = llList2String(particle_definitions, current_item);
-        parse_variable_definition(curr_line);
-        current_item++;
-    }
-}
-
-randomize_timer()
-{
-    if (randomize_colors) {
-        llSetTimerEvent(randomize_within_range(maximum_hold_time,
-            minimum_hold_time, FALSE));
-    }
-}
-
-stop_timer() { llSetTimerEvent(0.0); }
-
-check_for_notecard()
-{
-    if (current_notecard_name != "") return;
-    // if there's a notecard, then we will start reading it.
-    if (llGetInventoryNumber(INVENTORY_NOTECARD) > 0) {
-        current_notecard_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
-        line_number = 0;
-        query_contents = [];
-        current_query_id = llGetNotecardLine(current_notecard_name, 0);
-        llSetTimerEvent(80);
-    }
-}
-
-// this should be invoked from the link_message event handler to process the requests
-// for whatever service this library script provides.
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-    if (huff_id != PARTYCULIAR_HUFFWARE_ID) {
-        return;
-    }
-//llOwnerSay("link msg: " + (string)sender + " " + (string)huff_id + " msg=" + msg + " id=" + (string)id);
-    if (msg == PARTYCULIAR_POWER_COMMAND) {
-        string cmd = id;
-        if ( (find_substring(id, "on") == 0)
-            || (find_substring(id, "1") == 0)
-            || (find_substring(id, "true") == 0) ) {
-            // they want to crank the particle system up.
-            create_particle_system();
-            randomize_timer();
-        } else if ( (find_substring(id, "off") == 0)
-            || (find_substring(id, "0") == 0)
-            || (find_substring(id, "false") == 0) ) {
-            // the request is to shut the party down now.
-            llParticleSystem([]);
-            stop_timer();
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-//////////////
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-}
-
-//////////////
-
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-
-// handles when blank strings need to come through the pipe.
-string wrap_blank_string(string to_wrap)
-{
-    if (llStringLength(to_wrap)) return to_wrap;  // that one is okay.
-    return "\"\"";  // return a quoted nothing as a signal for a blank.
-}
-
-// undoes a previously wrapped blank string.
-string interpret_blank_string(string to_unwrap)
-{
-    if (to_unwrap == "\"\"") return "";  // that was an encoded blank.
-    return to_unwrap;  // no encoding.
-}
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply(integer destination, list parms, string command)
-{
-    llMessageLinked(destination, PARTYCULIAR_HUFFWARE_ID, command,
-        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-//////////////
-
-// returns a number at most maximum and at least minimum.
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// the string processing methods are not case sensitive.
-  
-// returns TRUE if the "pattern" is found in the "full_string".
-integer matches_substring(string full_string, string pattern)
-{ return (find_substring(full_string, pattern) >= 0); }
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return find_substring(compare_with, prefix) == 0; }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        initialize();
-        if (start_enabled) {
-            create_particle_system();
-            randomize_timer();
-        } else {
-            llParticleSystem([]);
-            stop_timer();
-        }
-        check_for_notecard();
-    }
-    
-    timer() {
-        if (current_query_id != NULL_KEY) {
-            // there's been a failure of some sort; we were supposed to get a notecard to read.
-            llWhisper(0, "Failed to read the notecard, now restarting.");
-            llResetScript();
-        }
-        create_particle_system();
-        randomize_timer();
-    }
-    
-    on_rez(integer parm) {
-        target_key = llGetKey();  // reset to get rid of weird wrong keys.
-        llResetScript();
-    }
-
-    link_message(integer sender, integer num, string msg, key id) {
-        handle_link_message(sender, num, msg, id);
-    }
-
-    changed(integer change_type) {
-        if (change_type != CHANGED_INVENTORY) {
-            // we only care about inventory changes here.
-            return;
-        }
-        llResetScript();
-    }
-    
-    dataserver(key query_id, string data) {
-        if (query_id != current_query_id) {
-log_it("not our query id somehow?  weird query had: id=" + (string)query_id + " data=" + (string)data);
-            // to heck with all this weirdness; if there's a failure, start over.
-            llResetScript();
-        }
-        // if we're not at the end of the notecard we're reading...
-        if (data != EOF) {
-            if (!line_number) {
-                if (data != "#party culiar") {
-                    // this card has the wrong signature at the top.  quit bothering
-                    // with it now.
-                    return;
-                }
-                log_it("starting to read notecard " + current_notecard_name + "...");    
-            }
-            if (data != "") {
-                 // add the non-blank line to our destination list.
-                query_contents += data;
-//log_it("line " + (string)line_number + ": data=" + data);
-            }
-            line_number++;  // increase the line count.
-            // request the next line from the notecard.
-            current_query_id = llGetNotecardLine(current_notecard_name, line_number);
-        } else {
-            // no more data, so we're done with this card.
-            current_query_id = NULL_KEY;
-            if (!llGetListLength(query_contents)) {
-                // nothing was read?  the heck with this card.
-                current_notecard_name = "";  // toss bad card.
-                return;
-            }
-//log_it("notecard said:\n" + dump_list(query_contents));
-            process_particle_settings(query_contents);
-            if (start_enabled) {
-                create_particle_system();
-                randomize_timer();
-            } else {
-                llParticleSystem([]);
-                stop_timer();
-            }
-            log_it("done reading notecard " + current_notecard_name + ".");
-        }
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/rotanium_rotato_v2.7.lsl b/huffware/huffotronic_updater_freebie_v5.3/rotanium_rotato_v2.7.lsl
new file mode 100755 (executable)
index 0000000..99ff84c
--- /dev/null
@@ -0,0 +1,258 @@
+
+// huffware script: rotanium rotato, by fred huffhines.
+//
+// causes the object to rotate according to the parameters set below.
+// this can use herky-jerky timed rotation with llSetRot or it can use
+// smooth rotation with llTargetOmega.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+integer RANDOMIZE_ROTATION = TRUE;
+
+integer SMOOTH_ROTATION = TRUE;
+    // if this is true, then the object will rotate smoothly rather than
+    // being rotated by the timer.
+
+float SMOOTH_TIMER_FREQUENCY = 14.0;
+    // the smooth rotater doesn't need to hit the timer all that often.
+
+float SMOOTH_CHANCE_FOR_ADJUSTING = 0.8;
+    // we won't always change the smooth rotation, even though our timer
+    // is pretty slow.
+
+float SMOOTH_ROTATION_GAIN_MAX = 0.0490873852122;
+    // the gain is how fast we will rotate in radians per second.
+    // PI / 2 is about 90 degrees per second, which seems way too fast.
+    // 0.196349540849 is about PI / 16, 0.0981747704244 is about PI / 32,
+    // and 0.0490873852122 is about PI / 64.
+
+float JERKY_TIMER_FREQUENCY = 0.50;
+    // this is the fastest that llSetRot rotation can happen anyhow,
+    // so we fire the timer at this rate.
+    
+float JERKY_CHANCE_FOR_ADJUSTING = 0.1;
+    // this is the probability of changing the current direction.
+
+vector current_add_in = <0.0, 0.0, 0.4>;
+    // randomly assigned to if RANDOMIZE_ROTATION is true.
+
+float current_gain = -0.05;
+    // speed of smooth rotation; will randomly change if RANDOMIZE_ROTATION is true.
+
+float MIN_ADDITION = 0.01;
+    // smallest amount of change we will ever have.
+float MAX_ADDITION = 7.0;
+    // largest amount of change we will ever have.
+
+// sets the gain and add in to random choices.
+randomize_values()
+{
+    current_gain = randomize_within_range(0.001, SMOOTH_ROTATION_GAIN_MAX, TRUE);
+    current_add_in = random_vector(MIN_ADDITION, MAX_ADDITION, TRUE);
+}
+
+// performs the timed rotation that has been configured for us.
+rotate_as_requested()
+{
+    if (SMOOTH_ROTATION) {
+        // our slack timer went off, so randomize the rotation if requested.
+        if (RANDOMIZE_ROTATION && (llFrand(1.0) >= SMOOTH_CHANCE_FOR_ADJUSTING) )
+            randomize_values();
+        // make sure we are using the rotational values we were asked to.
+        llTargetOmega(current_add_in, current_gain, 1.0);
+    } else {
+        // herky jerky rotation.
+    
+//hmmm: seeing that GetRot or GetLocalRot might be useful at different times.
+        rotation curr_rot = llGetLocalRot();  // get our current state.
+        vector euler_curr = llRot2Euler(curr_rot);  // turn into euler coords.
+        euler_curr *= RAD_TO_DEG;  // convert to degrees.
+        vector new_rot = euler_curr + current_add_in;  // add our adjustment in.
+        new_rot *= DEG_TO_RAD; // convert to radians.
+        rotation quat = llEuler2Rot(new_rot); // convert to quaternion
+        llSetLocalRot(quat);  // rotate the object
+//will the local work for a single prim?
+//in the current case, we do want just the local rot to change.
+    
+        // change the rotation add-in if the mood strikes us.
+        float starter = 0.420;  // where we start looking for change.
+        float change_cap = starter + JERKY_CHANCE_FOR_ADJUSTING;
+        float randomness = llFrand(1.000);
+        if ( (randomness <= change_cap) && (randomness >= starter) ) {
+            // time for a change in the rotation.
+            if (RANDOMIZE_ROTATION)
+                randomize_values();
+        }
+    }
+}
+
+//////////////
+// start of hufflets...
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// returns a random vector where x,y,z will be between "minimums" and "maximums"
+// x,y,z components.  if "allow_negative" is true, then any component will
+// randomly be negative or positive.
+vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
+{
+    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
+        randomize_within_range(minimums.y, maximums.y, allow_negative),
+        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
+}
+
+// returns a vector whose components are between minimum and maximum.
+// if allow_negative is true, then they can be either positive or negative.
+vector random_vector(float minimum, float maximum, integer allow_negative)
+{
+    return random_bound_vector(<minimum, minimum, minimum>,
+        <maximum, maximum, maximum>, allow_negative);
+}
+
+// end hufflets
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        // if needed, we will set our initial random rotation.
+        if (RANDOMIZE_ROTATION) randomize_values();
+        // do a first rotate, so we move right at startup.  otherwise we won't move
+        // until after our first timer hits.
+        rotate_as_requested();
+        // now set the timer for our mode.
+        if (SMOOTH_ROTATION) {
+            llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
+        } else {
+            llSetTimerEvent(JERKY_TIMER_FREQUENCY);
+        }
+    }
+
+    timer() { rotate_as_requested(); }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/rotanium_rotato_v2.7.txt b/huffware/huffotronic_updater_freebie_v5.3/rotanium_rotato_v2.7.txt
deleted file mode 100755 (executable)
index 99ff84c..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-
-// huffware script: rotanium rotato, by fred huffhines.
-//
-// causes the object to rotate according to the parameters set below.
-// this can use herky-jerky timed rotation with llSetRot or it can use
-// smooth rotation with llTargetOmega.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-integer RANDOMIZE_ROTATION = TRUE;
-
-integer SMOOTH_ROTATION = TRUE;
-    // if this is true, then the object will rotate smoothly rather than
-    // being rotated by the timer.
-
-float SMOOTH_TIMER_FREQUENCY = 14.0;
-    // the smooth rotater doesn't need to hit the timer all that often.
-
-float SMOOTH_CHANCE_FOR_ADJUSTING = 0.8;
-    // we won't always change the smooth rotation, even though our timer
-    // is pretty slow.
-
-float SMOOTH_ROTATION_GAIN_MAX = 0.0490873852122;
-    // the gain is how fast we will rotate in radians per second.
-    // PI / 2 is about 90 degrees per second, which seems way too fast.
-    // 0.196349540849 is about PI / 16, 0.0981747704244 is about PI / 32,
-    // and 0.0490873852122 is about PI / 64.
-
-float JERKY_TIMER_FREQUENCY = 0.50;
-    // this is the fastest that llSetRot rotation can happen anyhow,
-    // so we fire the timer at this rate.
-    
-float JERKY_CHANCE_FOR_ADJUSTING = 0.1;
-    // this is the probability of changing the current direction.
-
-vector current_add_in = <0.0, 0.0, 0.4>;
-    // randomly assigned to if RANDOMIZE_ROTATION is true.
-
-float current_gain = -0.05;
-    // speed of smooth rotation; will randomly change if RANDOMIZE_ROTATION is true.
-
-float MIN_ADDITION = 0.01;
-    // smallest amount of change we will ever have.
-float MAX_ADDITION = 7.0;
-    // largest amount of change we will ever have.
-
-// sets the gain and add in to random choices.
-randomize_values()
-{
-    current_gain = randomize_within_range(0.001, SMOOTH_ROTATION_GAIN_MAX, TRUE);
-    current_add_in = random_vector(MIN_ADDITION, MAX_ADDITION, TRUE);
-}
-
-// performs the timed rotation that has been configured for us.
-rotate_as_requested()
-{
-    if (SMOOTH_ROTATION) {
-        // our slack timer went off, so randomize the rotation if requested.
-        if (RANDOMIZE_ROTATION && (llFrand(1.0) >= SMOOTH_CHANCE_FOR_ADJUSTING) )
-            randomize_values();
-        // make sure we are using the rotational values we were asked to.
-        llTargetOmega(current_add_in, current_gain, 1.0);
-    } else {
-        // herky jerky rotation.
-    
-//hmmm: seeing that GetRot or GetLocalRot might be useful at different times.
-        rotation curr_rot = llGetLocalRot();  // get our current state.
-        vector euler_curr = llRot2Euler(curr_rot);  // turn into euler coords.
-        euler_curr *= RAD_TO_DEG;  // convert to degrees.
-        vector new_rot = euler_curr + current_add_in;  // add our adjustment in.
-        new_rot *= DEG_TO_RAD; // convert to radians.
-        rotation quat = llEuler2Rot(new_rot); // convert to quaternion
-        llSetLocalRot(quat);  // rotate the object
-//will the local work for a single prim?
-//in the current case, we do want just the local rot to change.
-    
-        // change the rotation add-in if the mood strikes us.
-        float starter = 0.420;  // where we start looking for change.
-        float change_cap = starter + JERKY_CHANCE_FOR_ADJUSTING;
-        float randomness = llFrand(1.000);
-        if ( (randomness <= change_cap) && (randomness >= starter) ) {
-            // time for a change in the rotation.
-            if (RANDOMIZE_ROTATION)
-                randomize_values();
-        }
-    }
-}
-
-//////////////
-// start of hufflets...
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// returns a random vector where x,y,z will be between "minimums" and "maximums"
-// x,y,z components.  if "allow_negative" is true, then any component will
-// randomly be negative or positive.
-vector random_bound_vector(vector minimums, vector maximums, integer allow_negative)
-{
-    return <randomize_within_range(minimums.x, maximums.x, allow_negative),
-        randomize_within_range(minimums.y, maximums.y, allow_negative),
-        randomize_within_range(minimums.z, maximums.z, allow_negative)>;
-}
-
-// returns a vector whose components are between minimum and maximum.
-// if allow_negative is true, then they can be either positive or negative.
-vector random_vector(float minimum, float maximum, integer allow_negative)
-{
-    return random_bound_vector(<minimum, minimum, minimum>,
-        <maximum, maximum, maximum>, allow_negative);
-}
-
-// end hufflets
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        // if needed, we will set our initial random rotation.
-        if (RANDOMIZE_ROTATION) randomize_values();
-        // do a first rotate, so we move right at startup.  otherwise we won't move
-        // until after our first timer hits.
-        rotate_as_requested();
-        // now set the timer for our mode.
-        if (SMOOTH_ROTATION) {
-            llSetTimerEvent(SMOOTH_TIMER_FREQUENCY);
-        } else {
-            llSetTimerEvent(JERKY_TIMER_FREQUENCY);
-        }
-    }
-
-    timer() { rotate_as_requested(); }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/take_touches_v0.2.lsl b/huffware/huffotronic_updater_freebie_v5.3/take_touches_v0.2.lsl
new file mode 100755 (executable)
index 0000000..62af88d
--- /dev/null
@@ -0,0 +1,19 @@
+
+// huffware script: take touches, by fred huffhines.
+//
+// eats any touches from an avatar so that other prims do not know they happened.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+default
+{
+    state_entry() { }
+
+    touch_start(integer total_number)
+    {
+        // do nothing.
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/take_touches_v0.2.txt b/huffware/huffotronic_updater_freebie_v5.3/take_touches_v0.2.txt
deleted file mode 100755 (executable)
index 62af88d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-
-// huffware script: take touches, by fred huffhines.
-//
-// eats any touches from an avatar so that other prims do not know they happened.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-default
-{
-    state_entry() { }
-
-    touch_start(integer total_number)
-    {
-        // do nothing.
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/text_label_v3.9.lsl b/huffware/huffotronic_updater_freebie_v5.3/text_label_v3.9.lsl
new file mode 100755 (executable)
index 0000000..0fddf07
--- /dev/null
@@ -0,0 +1,170 @@
+
+// huffware script: text label, by fred huffhines
+//
+// a super simple script for giving an object readable text.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+string OBJECT_LABEL = "default";  // change this if you want a specific name.
+
+vector LABEL_COLOR = <0.3, 0.9, 0.4>;  // color of the text above object.
+
+set_text()
+{
+    string object_label = OBJECT_LABEL;
+    // reset the label to a decorated version of object name if it was default.
+    if (object_label == "default") object_label = llGetObjectName();
+    integer indy;
+    integer keep_going = TRUE;
+    while (keep_going) {
+        indy = find_substring(object_label, "\\n");
+        if (indy < 0) {
+            keep_going = FALSE;
+        } else {
+            object_label = llGetSubString(object_label, 0, indy - 1)
+                + "\n" + llGetSubString(object_label, indy + 2, -1);
+        }
+    }
+//log_it("setting text: " + object_label);
+    llSetText(object_label, LABEL_COLOR, 1.0);
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// returns the index of the first occurrence of "pattern" inside
+// the "full_string".  if it is not found, then a negative number is returned.
+integer find_substring(string full_string, string pattern)
+{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.8.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//end hufflets...
+//////////////
+
+default
+{
+    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() { auto_retire(); set_text(); }
+    on_rez(integer start_parm) { state default; }
+    touch_start(integer count) { set_text(); }
+    changed(integer change) { if (change & CHANGED_INVENTORY) set_text(); }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/text_label_v3.9.txt b/huffware/huffotronic_updater_freebie_v5.3/text_label_v3.9.txt
deleted file mode 100755 (executable)
index 0fddf07..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-
-// huffware script: text label, by fred huffhines
-//
-// a super simple script for giving an object readable text.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-string OBJECT_LABEL = "default";  // change this if you want a specific name.
-
-vector LABEL_COLOR = <0.3, 0.9, 0.4>;  // color of the text above object.
-
-set_text()
-{
-    string object_label = OBJECT_LABEL;
-    // reset the label to a decorated version of object name if it was default.
-    if (object_label == "default") object_label = llGetObjectName();
-    integer indy;
-    integer keep_going = TRUE;
-    while (keep_going) {
-        indy = find_substring(object_label, "\\n");
-        if (indy < 0) {
-            keep_going = FALSE;
-        } else {
-            object_label = llGetSubString(object_label, 0, indy - 1)
-                + "\n" + llGetSubString(object_label, indy + 2, -1);
-        }
-    }
-//log_it("setting text: " + object_label);
-    llSetText(object_label, LABEL_COLOR, 1.0);
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-//llWhisper(0, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetDate() + ": " + llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// returns the index of the first occurrence of "pattern" inside
-// the "full_string".  if it is not found, then a negative number is returned.
-integer find_substring(string full_string, string pattern)
-{ return llSubStringIndex(llToLower(full_string), llToLower(pattern)); }
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.8.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//end hufflets...
-//////////////
-
-default
-{
-    state_entry() { if (llSubStringIndex(llGetObjectName(),  "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); set_text(); }
-    on_rez(integer start_parm) { state default; }
-    touch_start(integer count) { set_text(); }
-    changed(integer change) { if (change & CHANGED_INVENTORY) set_text(); }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/texture_mover_v3.0.lsl b/huffware/huffotronic_updater_freebie_v5.3/texture_mover_v3.0.lsl
new file mode 100755 (executable)
index 0000000..57a1e64
--- /dev/null
@@ -0,0 +1,237 @@
+
+// huffware script: texture mover, by fred huffhines
+//
+// moves a texture across the object, either by smooth animation or brute force offsetting.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+// constants...
+
+integer USE_TEXTURE_ANIMATION = TRUE;
+    // by default, we use texture animation which is a lower-lag way to
+    // make the texture move.  if this is false, then we use a timed update
+    // to move the texture instead.
+    // note: these modes are actually really different.  the texture animation
+    // is included here because i wanted to smooth out some objects that used
+    // texture movement.
+
+// used in both types...
+
+float TIMER_INTERVAL = 0.2;  // how fast do we move texture?
+
+// for timed movement...
+
+vector OFFSET_MOVEMENT = ZERO_VECTOR;  // no movement.
+//vector OFFSET_MOVEMENT = <0.0, -0.02, 0.0>;
+    // how much to move the texture by in x,y,z directions.
+
+//float OFFSET_ROTATION = 0.0;  // in degrees.
+float OFFSET_ROTATION = -1.0;  // in degrees.
+
+// for texture animations...
+
+float MOVER_TIMER_DIVISOR = 30.0;
+    // makes the movement comparable to timed method.
+
+float ROTATER_TIMER_DIVISOR = 7.0;
+    // makes the rotation comparable to timed method.
+
+// iterative movement of texture.
+move_texture(vector offset)
+{
+    vector current = llGetTextureOffset(ALL_SIDES);
+    current += offset;
+    if (current.x > 1.0) current.x = -1.0;
+    if (current.x < -1.0) current.x = 1.0;
+    if (current.y > 1.0) current.y = -1.0;
+    if (current.y < -1.0) current.y = 1.0;
+    llOffsetTexture(current.x, current.y, ALL_SIDES);
+}
+
+// iterative rotation of texture.  "spin" is measured in degrees.
+spin_texture(float spin)
+{
+    float rot = llGetTextureRot(ALL_SIDES);  // get our current state.
+    rot += spin * DEG_TO_RAD;  // add some rotation.
+    llRotateTexture(rot, ALL_SIDES); //rotate the object   
+}
+
+initialize_texture_mover()
+{
+    if (!USE_TEXTURE_ANIMATION) {
+        // we're stuck with the timed update style for movement.
+        llSetTimerEvent(TIMER_INTERVAL);
+        // turn off previous animation.
+        llSetTextureAnim(0, ALL_SIDES, 0, 0, 0, 0, 0);
+    } else {
+        // we can just set the texture movement here and be done with it.
+        integer x_frames = 1;
+        integer y_frames = 1;
+        llSetTimerEvent(0);  // we don't use a timer.
+
+//hmmm: how do we combine rotation and offsets?  currently mutually exclusive.
+
+        if (OFFSET_MOVEMENT != ZERO_VECTOR) {
+            float timer_interval = TIMER_INTERVAL / MOVER_TIMER_DIVISOR;
+log_it("getting x_frames=" + (string)x_frames
++ " y_frames=" + (string)y_frames
++ " timer_intvl=" + (string)timer_interval);
+
+            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES,
+                x_frames, y_frames,
+                0, 100, timer_interval);
+        } else if (OFFSET_ROTATION != 0.0) {
+            float timer_interval = TIMER_INTERVAL / ROTATER_TIMER_DIVISOR;
+            // we're actually not using the rotation at all here, except for
+            // the sign.  that seems pretty busted.
+            if (OFFSET_ROTATION < 0) timer_interval *= -1.0;
+            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE, ALL_SIDES,
+                0, 0,
+                0, TWO_PI, timer_interval);
+        }
+    }
+}
+
+//////////////
+// from hufflets...
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+//
+//////////////
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();
+        initialize_texture_mover();
+    }
+
+    timer() {
+        // the timed approach is the only one so far that allows both a
+        // movement of the texture and a rotation.
+        if (OFFSET_MOVEMENT != ZERO_VECTOR) move_texture(OFFSET_MOVEMENT);
+        if (OFFSET_ROTATION != 0.0) spin_texture(OFFSET_ROTATION);
+    }
+}
+
diff --git a/huffware/huffotronic_updater_freebie_v5.3/texture_mover_v3.0.txt b/huffware/huffotronic_updater_freebie_v5.3/texture_mover_v3.0.txt
deleted file mode 100755 (executable)
index 57a1e64..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-
-// huffware script: texture mover, by fred huffhines
-//
-// moves a texture across the object, either by smooth animation or brute force offsetting.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// constants...
-
-integer USE_TEXTURE_ANIMATION = TRUE;
-    // by default, we use texture animation which is a lower-lag way to
-    // make the texture move.  if this is false, then we use a timed update
-    // to move the texture instead.
-    // note: these modes are actually really different.  the texture animation
-    // is included here because i wanted to smooth out some objects that used
-    // texture movement.
-
-// used in both types...
-
-float TIMER_INTERVAL = 0.2;  // how fast do we move texture?
-
-// for timed movement...
-
-vector OFFSET_MOVEMENT = ZERO_VECTOR;  // no movement.
-//vector OFFSET_MOVEMENT = <0.0, -0.02, 0.0>;
-    // how much to move the texture by in x,y,z directions.
-
-//float OFFSET_ROTATION = 0.0;  // in degrees.
-float OFFSET_ROTATION = -1.0;  // in degrees.
-
-// for texture animations...
-
-float MOVER_TIMER_DIVISOR = 30.0;
-    // makes the movement comparable to timed method.
-
-float ROTATER_TIMER_DIVISOR = 7.0;
-    // makes the rotation comparable to timed method.
-
-// iterative movement of texture.
-move_texture(vector offset)
-{
-    vector current = llGetTextureOffset(ALL_SIDES);
-    current += offset;
-    if (current.x > 1.0) current.x = -1.0;
-    if (current.x < -1.0) current.x = 1.0;
-    if (current.y > 1.0) current.y = -1.0;
-    if (current.y < -1.0) current.y = 1.0;
-    llOffsetTexture(current.x, current.y, ALL_SIDES);
-}
-
-// iterative rotation of texture.  "spin" is measured in degrees.
-spin_texture(float spin)
-{
-    float rot = llGetTextureRot(ALL_SIDES);  // get our current state.
-    rot += spin * DEG_TO_RAD;  // add some rotation.
-    llRotateTexture(rot, ALL_SIDES); //rotate the object   
-}
-
-initialize_texture_mover()
-{
-    if (!USE_TEXTURE_ANIMATION) {
-        // we're stuck with the timed update style for movement.
-        llSetTimerEvent(TIMER_INTERVAL);
-        // turn off previous animation.
-        llSetTextureAnim(0, ALL_SIDES, 0, 0, 0, 0, 0);
-    } else {
-        // we can just set the texture movement here and be done with it.
-        integer x_frames = 1;
-        integer y_frames = 1;
-        llSetTimerEvent(0);  // we don't use a timer.
-
-//hmmm: how do we combine rotation and offsets?  currently mutually exclusive.
-
-        if (OFFSET_MOVEMENT != ZERO_VECTOR) {
-            float timer_interval = TIMER_INTERVAL / MOVER_TIMER_DIVISOR;
-log_it("getting x_frames=" + (string)x_frames
-+ " y_frames=" + (string)y_frames
-+ " timer_intvl=" + (string)timer_interval);
-
-            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH, ALL_SIDES,
-                x_frames, y_frames,
-                0, 100, timer_interval);
-        } else if (OFFSET_ROTATION != 0.0) {
-            float timer_interval = TIMER_INTERVAL / ROTATER_TIMER_DIVISOR;
-            // we're actually not using the rotation at all here, except for
-            // the sign.  that seems pretty busted.
-            if (OFFSET_ROTATION < 0) timer_interval *= -1.0;
-            llSetTextureAnim(ANIM_ON | LOOP | SMOOTH | ROTATE, ALL_SIDES,
-                0, 0,
-                0, TWO_PI, timer_interval);
-        }
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-//
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();
-        initialize_texture_mover();
-    }
-
-    timer() {
-        // the timed approach is the only one so far that allows both a
-        // movement of the texture and a rotation.
-        if (OFFSET_MOVEMENT != ZERO_VECTOR) move_texture(OFFSET_MOVEMENT);
-        if (OFFSET_ROTATION != 0.0) spin_texture(OFFSET_ROTATION);
-    }
-}
-
diff --git a/huffware/huffotronic_updater_freebie_v5.3/texture_shower_v2.7.lsl b/huffware/huffotronic_updater_freebie_v5.3/texture_shower_v2.7.lsl
new file mode 100755 (executable)
index 0000000..629dd58
--- /dev/null
@@ -0,0 +1,480 @@
+
+// huffware script: texture shower, by fred huffhines.
+//
+// displays a texture from its inventory when the name is spoken in chat.
+//
+// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+// do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+
+// global constants...
+
+string SHOWER_SIGNATURE = "#texture_shower";
+    // the notecard must begin with this as its first line for it to be
+    // recognized as our configuration card.
+
+// global variables...
+
+string global_notecard_name;  // name of our notecard in the object's inventory.
+integer response_code;  // set to uniquely identify the notecard read in progress.
+list global_config_list;  // a collection of configuration parameters from our notecard.
+integer global_config_index;  // allows wrap-around feature, which we don't use here.
+
+list texture_names;  // the set of textures we've got in inventory.
+
+integer LISTENING_CHANNEL = 1008;
+    // the default listening channel is hardly ever used; the channel should
+    // come from the notecard.
+
+//////////////
+
+// processes the variables that come from the notecard.
+parse_variable_definition(string to_parse)
+{
+    string content;  // filled after finding a variable name.
+    if ( (content = get_variable_value(to_parse, "channel")) != "") {
+//        log_it("channel=" + content);
+        LISTENING_CHANNEL = (integer)content;
+    }
+}
+
+//////////////
+
+// sets the viewing sides' textures to a particular inventory item.
+set_texture_to_item(string inv_tex)
+{
+    llSetTexture(inv_tex, 1);
+    llSetTexture(inv_tex, 3);
+}
+
+// sets our viewing sides back to the default texture.
+reset_textures()
+{
+    string tex_cur = llGetTexture(0);
+    set_texture_to_item(tex_cur);
+}
+
+// startup for the very early part of the object's lifetime.
+initialize_phase_1()
+{
+    // reset our relevant variables.
+    global_notecard_name = "";
+    global_config_list = [];
+    global_config_index = 0;
+    texture_names = [];
+
+    // request that the noteworthy library start looking for our notecard.
+    request_configuration();
+
+//    log_it("started, free mem=" + (string)llGetFreeMemory());
+}
+
+// this gets us ready to enter our active state.
+initialize_phase_2()
+{
+    // listen for commands on the channel we're configured for.
+    llListen(LISTENING_CHANNEL, "", NULL_KEY, "");
+    // load all the texture names we know about.    
+    integer texture_count = llGetInventoryNumber(INVENTORY_TEXTURE);
+    integer indy;
+    for (indy = 0; indy < texture_count; indy++)
+        texture_names += llGetInventoryName(INVENTORY_TEXTURE, indy);
+}
+
+manage_those_voices(integer channel, string message)
+{
+    if (channel != LISTENING_CHANNEL) return;  // not for us.
+    if (message == "reset-texture") {
+        reset_textures();
+        return;
+    }
+    // wasn't a command to reset, so let's see if we know it.
+    integer texture_count = llGetListLength(texture_names);
+    integer indy;
+    for (indy = 0; indy < texture_count; indy++) {
+        integer posn = llListFindList(texture_names, (message));
+        if (posn >= 0) {
+            // found one...
+            set_texture_to_item(message);
+            return;
+        }
+    }    
+}
+
+//////////////
+
+// this chunk largely comes from the example noteworthy usage...
+
+// requires noteworthy library v8.4 or better.
+//////////////
+// do not redefine these constants.
+integer NOTEWORTHY_HUFFWARE_ID = 10010;
+    // the unique id within the huffware system for the noteworthy script to
+    // accept commands on.  this is used in llMessageLinked as the num parameter.
+string HUFFWARE_PARM_SEPARATOR = "{~~~}";
+    // this pattern is an uncommon thing to see in text, so we use it to separate
+    // our commands in link messages.
+string HUFFWARE_ITEM_SEPARATOR = "{|||}";
+    // used to separate lists of items from each other when stored inside a parameter.
+    // this allows lists to be passed as single string parameters if needed.
+integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
+// commands available via the noteworthy library:
+string READ_NOTECARD_COMMAND = "#read_note#";
+    // command used to tell the script to read notecards.  needs a signature to find
+    // in the card as the first parameter, and a randomly generated response code for
+    // the second parameter.  the response code is used to uniquely identify a set of
+    // pending notecard readings (hopefully).  the signature can be empty or missing.
+    // the results will be fired back as the string value returned, which will have
+    // as first element the notecard's name (or "bad_notecard" if none was found) and
+    // as subsequent elements an embedded list that was read from the notecard.  this
+    // necessarily limits the size of the notecards that we can read and return.
+//
+//////////////
+// joins a list of parameters using the parameter sentinel for the library.
+string wrap_parameters(list to_flatten)
+{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
+//////////////
+
+// this function fires off a request to the noteworthy library via a link message.
+// noteworthy will look for a notecard with our particular signature in it and
+// if it finds one, it will read the configuration therein.  an empty string is
+// returned if noteworthy couldn't find anything.
+request_configuration()
+{
+    global_notecard_name = "";  // reset any previous card.
+    // try to find a notecard with our configuration.
+    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
+    string parms_sent = wrap_parameters([SHOWER_SIGNATURE, response_code]);
+    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
+         parms_sent);
+}
+
+// processes link messages received from the noteworthy library and others.
+// if the message indicates we should change states, then TRUE is returned.
+integer handle_link_message(integer which, integer num, string msg, key id)
+{
+    if (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
+        return FALSE;  // not for us.
+    // process the result of reading the notecard.
+    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
+    string notecard_name = llList2String(parms, 0);
+    integer response_for = llList2Integer(parms, 1);
+    if (response_for != response_code) return FALSE;  // oops, this isn't for us.
+    if (notecard_name != "bad_notecard") {
+        // a valid notecard has been found.
+        global_notecard_name = notecard_name;  // record its name for later use.
+        global_config_index = 0;  // we are starting over in the config list.
+        // snag all but the first two elements for our config now.
+        global_config_list = llList2List(parms, 2, -1);
+        // and process the file as a set of definitions.
+        process_ini_config();
+        return TRUE;
+    } else {
+        // we hated the notecards we found, or there were none.
+        log_it("We apologize; there seem to be no notecards with a first line of '"
+            + SHOWER_SIGNATURE
+            + "'.  We can't read any configuration until that situation improves.");
+    }
+    return FALSE;
+}
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+//log_it("invpo=" + (string)posn);
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+//log_it("pos=" + (string)space_v_posn);
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+//log_it("space v@" + (string)space_v_posn);
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+//log_it("indy=" + (string)space_v_posn);
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+//////////////
+// from hufflets...
+//
+
+integer debug_num = 0;
+
+// a debugging output method.  can be disabled entirely in one place.
+log_it(string to_say)
+{
+    debug_num++;
+    // tell this to the owner.    
+    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on an unusual channel for chat if it's not intended for general public.
+//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
+    // say this on open chat that anyone can hear.  we take off the bling for this one.
+//    llSay(0, to_say);
+}
+
+// locates the string "text" in the list to "search_in".
+integer find_in_list(list search_in, string text)
+{ 
+    integer len = llGetListLength(search_in);
+    integer i; 
+    for (i = 0; i < len; i++) { 
+        if (llList2String(search_in, i) == text) 
+            return i; 
+    } 
+    return -1;
+}
+
+// returns TRUE if the "prefix" string is the first part of "compare_with".
+integer is_prefix(string compare_with, string prefix)
+{ return (llSubStringIndex(compare_with, prefix) == 0); }
+
+// returns a number at most "maximum" and at least "minimum".
+// if "allow_negative" is TRUE, then the return may be positive or negative.
+float randomize_within_range(float minimum, float maximum, integer allow_negative)
+{
+    if (minimum > maximum) {
+        // flip the two if they are reversed.
+        float temp = minimum; minimum = maximum; maximum = temp;
+    }
+    float to_return = minimum + llFrand(maximum - minimum);
+    if (allow_negative) {
+        if (llFrand(1.0) < 0.5) to_return *= -1.0;
+    }
+    return to_return;
+}
+
+// strips the spaces off of the beginning and end of a string.
+string strip_spaces(string to_strip)
+{
+    // clean out initial spaces.
+    while (llGetSubString(to_strip, 0, 0) == " ")
+        to_strip = llDeleteSubString(to_strip, 0, 0);
+    // clean out ending spaces.
+    while (llGetSubString(to_strip, -1, -1) == " ")
+        to_strip = llDeleteSubString(to_strip, -1, -1);
+    return to_strip;
+}
+
+// parses a variable definition to find the name of the variable and its value.
+// this returns two strings [X, Y], if "to_split" is in the form X=Y.
+list separate_variable_definition(string to_split)
+{
+    integer equals_indy = llSubStringIndex(to_split, "=");
+    // we don't support missing an equals sign, and we don't support it as the first character.
+    if (equals_indy <= 0) return [];  // no match.
+    string x = llGetSubString(to_split, 0, equals_indy - 1);
+    string y = llGetSubString(to_split, equals_indy + 1, -1);
+    to_split = "";  // save space.
+    return [ strip_spaces(x), strip_spaces(y) ];
+}
+
+// returns a non-empty string if "to_check" defines a value for "variable_name".
+// this must be in the form "X=Y", where X is the variable_name and Y is the value.
+string get_variable_value(string to_check, string variable_name)
+{
+    list x_y = separate_variable_definition(to_check);
+    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
+    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
+    return llList2String(x_y, 1);  // a match!
+}
+
+// examines all entries that we got from the notecard to see if any contain definitions.
+// this is basically an INI file reader, but it uses a list instead of a file.
+// ini files provide a format with multiple sections of config information, like so:
+//    [section_1]
+//    name1=value1
+//    name2=value2 ...etc...
+//    [section_2]
+//    name1=value1 ...etc...
+process_ini_config()
+{
+//    log_it("scanning notecard for variable definitions...");
+    integer indy;
+    integer count = llGetListLength(global_config_list);
+
+    // iterate across the items in our configuration to look for ones that are not done yet.            
+    for (indy = global_config_index; indy < count; indy++) {
+        string line = llList2String(global_config_list, indy);
+        // search for a section beginning.
+        if (llGetSubString(line, 0, 0) == "[") {
+            // we found the start of a section name.  now read the contents.
+            indy++;  // skip section line.
+            log_it("reading section: " + llGetSubString(line, 1, -2));
+        }
+        integer sec_indy;
+        for (sec_indy = indy; sec_indy < count; sec_indy++) {
+            // read the lines in the section.
+            line = llList2String(global_config_list, sec_indy);
+            if (llGetSubString(line, 0, 0) != "[") {
+                // try to interpret this line as a variable setting.  this is just
+                // one example of a way to handle the config file; one might instead
+                // want to do something below once a whole section is read.
+                parse_variable_definition(line);
+            } else {
+                // we're at the beginning of a new section now, so start processing its
+                // configuration in the outer loop.
+                indy = sec_indy - 1;  // set indy to proper beginning of section.
+                global_config_index = indy;  // remember where we had read to.
+                sec_indy = count + 3;  // skip remainder of inner loop.
+            }
+        }
+    }
+
+    global_config_index = 0;  // reset outer position if want to re-read.
+}
+
+// locates the item with "name_to_find" in the inventory items with the "type".
+// a value from 0 to N-1 is returned if it's found, where N is the number of
+// items in the inventory.
+integer find_in_inventory(string name_to_find, integer inv_type)
+{
+    integer num_inv = llGetInventoryNumber(inv_type);
+    if (num_inv == 0) return -1;  // nothing there!
+    integer inv;
+    for (inv = 0; inv < num_inv; inv++) {
+        if (llGetInventoryName(inv_type, inv) == name_to_find)
+            return inv;
+    }
+    return -2;  // failed to find it.
+}
+// end hufflets
+//////////////
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry() {
+        auto_retire();  // make sure newest addition is only version of script.
+        initialize_phase_1();
+    }
+
+    on_rez(integer param) { state rerun; }
+    
+    // reset when we see changes to our notecard configuration.
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
+            state rerun;
+        }
+    }
+
+    // process the response from the noteworthy library.
+    link_message(integer which, integer num, string msg, key id) {
+        integer retval = handle_link_message(which, num, msg, id);
+        if (retval) state configured;  // skip states if we were asked to.
+    }
+}
+
+state configured
+{
+    state_entry() {
+        initialize_phase_2();
+    }
+    
+    listen(integer channel, string name, key id, string message) {
+        manage_those_voices(channel, message);
+    }
+
+    link_message(integer which, integer num, string msg, key id) {
+        manage_those_voices(num, msg);
+    }
+
+    // reset when we see changes to our notecard configuration.
+    changed(integer change) {
+        if (change & CHANGED_INVENTORY) {
+            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
+            state default;
+        }
+    }
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/texture_shower_v2.7.txt b/huffware/huffotronic_updater_freebie_v5.3/texture_shower_v2.7.txt
deleted file mode 100755 (executable)
index 629dd58..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-
-// huffware script: texture shower, by fred huffhines.
-//
-// displays a texture from its inventory when the name is spoken in chat.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-
-// global constants...
-
-string SHOWER_SIGNATURE = "#texture_shower";
-    // the notecard must begin with this as its first line for it to be
-    // recognized as our configuration card.
-
-// global variables...
-
-string global_notecard_name;  // name of our notecard in the object's inventory.
-integer response_code;  // set to uniquely identify the notecard read in progress.
-list global_config_list;  // a collection of configuration parameters from our notecard.
-integer global_config_index;  // allows wrap-around feature, which we don't use here.
-
-list texture_names;  // the set of textures we've got in inventory.
-
-integer LISTENING_CHANNEL = 1008;
-    // the default listening channel is hardly ever used; the channel should
-    // come from the notecard.
-
-//////////////
-
-// processes the variables that come from the notecard.
-parse_variable_definition(string to_parse)
-{
-    string content;  // filled after finding a variable name.
-    if ( (content = get_variable_value(to_parse, "channel")) != "") {
-//        log_it("channel=" + content);
-        LISTENING_CHANNEL = (integer)content;
-    }
-}
-
-//////////////
-
-// sets the viewing sides' textures to a particular inventory item.
-set_texture_to_item(string inv_tex)
-{
-    llSetTexture(inv_tex, 1);
-    llSetTexture(inv_tex, 3);
-}
-
-// sets our viewing sides back to the default texture.
-reset_textures()
-{
-    string tex_cur = llGetTexture(0);
-    set_texture_to_item(tex_cur);
-}
-
-// startup for the very early part of the object's lifetime.
-initialize_phase_1()
-{
-    // reset our relevant variables.
-    global_notecard_name = "";
-    global_config_list = [];
-    global_config_index = 0;
-    texture_names = [];
-
-    // request that the noteworthy library start looking for our notecard.
-    request_configuration();
-
-//    log_it("started, free mem=" + (string)llGetFreeMemory());
-}
-
-// this gets us ready to enter our active state.
-initialize_phase_2()
-{
-    // listen for commands on the channel we're configured for.
-    llListen(LISTENING_CHANNEL, "", NULL_KEY, "");
-    // load all the texture names we know about.    
-    integer texture_count = llGetInventoryNumber(INVENTORY_TEXTURE);
-    integer indy;
-    for (indy = 0; indy < texture_count; indy++)
-        texture_names += llGetInventoryName(INVENTORY_TEXTURE, indy);
-}
-
-manage_those_voices(integer channel, string message)
-{
-    if (channel != LISTENING_CHANNEL) return;  // not for us.
-    if (message == "reset-texture") {
-        reset_textures();
-        return;
-    }
-    // wasn't a command to reset, so let's see if we know it.
-    integer texture_count = llGetListLength(texture_names);
-    integer indy;
-    for (indy = 0; indy < texture_count; indy++) {
-        integer posn = llListFindList(texture_names, (message));
-        if (posn >= 0) {
-            // found one...
-            set_texture_to_item(message);
-            return;
-        }
-    }    
-}
-
-//////////////
-
-// this chunk largely comes from the example noteworthy usage...
-
-// requires noteworthy library v8.4 or better.
-//////////////
-// do not redefine these constants.
-integer NOTEWORTHY_HUFFWARE_ID = 10010;
-    // the unique id within the huffware system for the noteworthy script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-// commands available via the noteworthy library:
-string READ_NOTECARD_COMMAND = "#read_note#";
-    // command used to tell the script to read notecards.  needs a signature to find
-    // in the card as the first parameter, and a randomly generated response code for
-    // the second parameter.  the response code is used to uniquely identify a set of
-    // pending notecard readings (hopefully).  the signature can be empty or missing.
-    // the results will be fired back as the string value returned, which will have
-    // as first element the notecard's name (or "bad_notecard" if none was found) and
-    // as subsequent elements an embedded list that was read from the notecard.  this
-    // necessarily limits the size of the notecards that we can read and return.
-//
-//////////////
-// joins a list of parameters using the parameter sentinel for the library.
-string wrap_parameters(list to_flatten)
-{ return llDumpList2String(to_flatten, HUFFWARE_PARM_SEPARATOR); }
-//////////////
-
-// this function fires off a request to the noteworthy library via a link message.
-// noteworthy will look for a notecard with our particular signature in it and
-// if it finds one, it will read the configuration therein.  an empty string is
-// returned if noteworthy couldn't find anything.
-request_configuration()
-{
-    global_notecard_name = "";  // reset any previous card.
-    // try to find a notecard with our configuration.
-    response_code = -1 * (integer)randomize_within_range(23, 80000, FALSE);
-    string parms_sent = wrap_parameters([SHOWER_SIGNATURE, response_code]);
-    llMessageLinked(LINK_THIS, NOTEWORTHY_HUFFWARE_ID, READ_NOTECARD_COMMAND,
-         parms_sent);
-}
-
-// processes link messages received from the noteworthy library and others.
-// if the message indicates we should change states, then TRUE is returned.
-integer handle_link_message(integer which, integer num, string msg, key id)
-{
-    if (num != NOTEWORTHY_HUFFWARE_ID + REPLY_DISTANCE)
-        return FALSE;  // not for us.
-    // process the result of reading the notecard.
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    string notecard_name = llList2String(parms, 0);
-    integer response_for = llList2Integer(parms, 1);
-    if (response_for != response_code) return FALSE;  // oops, this isn't for us.
-    if (notecard_name != "bad_notecard") {
-        // a valid notecard has been found.
-        global_notecard_name = notecard_name;  // record its name for later use.
-        global_config_index = 0;  // we are starting over in the config list.
-        // snag all but the first two elements for our config now.
-        global_config_list = llList2List(parms, 2, -1);
-        // and process the file as a set of definitions.
-        process_ini_config();
-        return TRUE;
-    } else {
-        // we hated the notecards we found, or there were none.
-        log_it("We apologize; there seem to be no notecards with a first line of '"
-            + SHOWER_SIGNATURE
-            + "'.  We can't read any configuration until that situation improves.");
-    }
-    return FALSE;
-}
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-//log_it("invpo=" + (string)posn);
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-//log_it("pos=" + (string)space_v_posn);
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-//log_it("space v@" + (string)space_v_posn);
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-//log_it("indy=" + (string)space_v_posn);
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-//log_it("saw case of previously redundant item, aieee.  flattened: " + to_chop_up);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-//////////////
-// from hufflets...
-//
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on an unusual channel for chat if it's not intended for general public.
-//    llSay(108, llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat that anyone can hear.  we take off the bling for this one.
-//    llSay(0, to_say);
-}
-
-// locates the string "text" in the list to "search_in".
-integer find_in_list(list search_in, string text)
-{ 
-    integer len = llGetListLength(search_in);
-    integer i; 
-    for (i = 0; i < len; i++) { 
-        if (llList2String(search_in, i) == text) 
-            return i; 
-    } 
-    return -1;
-}
-
-// returns TRUE if the "prefix" string is the first part of "compare_with".
-integer is_prefix(string compare_with, string prefix)
-{ return (llSubStringIndex(compare_with, prefix) == 0); }
-
-// returns a number at most "maximum" and at least "minimum".
-// if "allow_negative" is TRUE, then the return may be positive or negative.
-float randomize_within_range(float minimum, float maximum, integer allow_negative)
-{
-    if (minimum > maximum) {
-        // flip the two if they are reversed.
-        float temp = minimum; minimum = maximum; maximum = temp;
-    }
-    float to_return = minimum + llFrand(maximum - minimum);
-    if (allow_negative) {
-        if (llFrand(1.0) < 0.5) to_return *= -1.0;
-    }
-    return to_return;
-}
-
-// strips the spaces off of the beginning and end of a string.
-string strip_spaces(string to_strip)
-{
-    // clean out initial spaces.
-    while (llGetSubString(to_strip, 0, 0) == " ")
-        to_strip = llDeleteSubString(to_strip, 0, 0);
-    // clean out ending spaces.
-    while (llGetSubString(to_strip, -1, -1) == " ")
-        to_strip = llDeleteSubString(to_strip, -1, -1);
-    return to_strip;
-}
-
-// parses a variable definition to find the name of the variable and its value.
-// this returns two strings [X, Y], if "to_split" is in the form X=Y.
-list separate_variable_definition(string to_split)
-{
-    integer equals_indy = llSubStringIndex(to_split, "=");
-    // we don't support missing an equals sign, and we don't support it as the first character.
-    if (equals_indy <= 0) return [];  // no match.
-    string x = llGetSubString(to_split, 0, equals_indy - 1);
-    string y = llGetSubString(to_split, equals_indy + 1, -1);
-    to_split = "";  // save space.
-    return [ strip_spaces(x), strip_spaces(y) ];
-}
-
-// returns a non-empty string if "to_check" defines a value for "variable_name".
-// this must be in the form "X=Y", where X is the variable_name and Y is the value.
-string get_variable_value(string to_check, string variable_name)
-{
-    list x_y = separate_variable_definition(to_check);
-    if (llGetListLength(x_y) != 2) return "";  // failure to parse a variable def at all.
-    if (!is_prefix(llList2String(x_y, 0), variable_name)) return "";  // no match.
-    return llList2String(x_y, 1);  // a match!
-}
-
-// examines all entries that we got from the notecard to see if any contain definitions.
-// this is basically an INI file reader, but it uses a list instead of a file.
-// ini files provide a format with multiple sections of config information, like so:
-//    [section_1]
-//    name1=value1
-//    name2=value2 ...etc...
-//    [section_2]
-//    name1=value1 ...etc...
-process_ini_config()
-{
-//    log_it("scanning notecard for variable definitions...");
-    integer indy;
-    integer count = llGetListLength(global_config_list);
-
-    // iterate across the items in our configuration to look for ones that are not done yet.            
-    for (indy = global_config_index; indy < count; indy++) {
-        string line = llList2String(global_config_list, indy);
-        // search for a section beginning.
-        if (llGetSubString(line, 0, 0) == "[") {
-            // we found the start of a section name.  now read the contents.
-            indy++;  // skip section line.
-            log_it("reading section: " + llGetSubString(line, 1, -2));
-        }
-        integer sec_indy;
-        for (sec_indy = indy; sec_indy < count; sec_indy++) {
-            // read the lines in the section.
-            line = llList2String(global_config_list, sec_indy);
-            if (llGetSubString(line, 0, 0) != "[") {
-                // try to interpret this line as a variable setting.  this is just
-                // one example of a way to handle the config file; one might instead
-                // want to do something below once a whole section is read.
-                parse_variable_definition(line);
-            } else {
-                // we're at the beginning of a new section now, so start processing its
-                // configuration in the outer loop.
-                indy = sec_indy - 1;  // set indy to proper beginning of section.
-                global_config_index = indy;  // remember where we had read to.
-                sec_indy = count + 3;  // skip remainder of inner loop.
-            }
-        }
-    }
-
-    global_config_index = 0;  // reset outer position if want to re-read.
-}
-
-// locates the item with "name_to_find" in the inventory items with the "type".
-// a value from 0 to N-1 is returned if it's found, where N is the number of
-// items in the inventory.
-integer find_in_inventory(string name_to_find, integer inv_type)
-{
-    integer num_inv = llGetInventoryNumber(inv_type);
-    if (num_inv == 0) return -1;  // nothing there!
-    integer inv;
-    for (inv = 0; inv < num_inv; inv++) {
-        if (llGetInventoryName(inv_type, inv) == name_to_find)
-            return inv;
-    }
-    return -2;  // failed to find it.
-}
-// end hufflets
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() {
-        auto_retire();  // make sure newest addition is only version of script.
-        initialize_phase_1();
-    }
-
-    on_rez(integer param) { state rerun; }
-    
-    // reset when we see changes to our notecard configuration.
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
-            state rerun;
-        }
-    }
-
-    // process the response from the noteworthy library.
-    link_message(integer which, integer num, string msg, key id) {
-        integer retval = handle_link_message(which, num, msg, id);
-        if (retval) state configured;  // skip states if we were asked to.
-    }
-}
-
-state configured
-{
-    state_entry() {
-        initialize_phase_2();
-    }
-    
-    listen(integer channel, string name, key id, string message) {
-        manage_those_voices(channel, message);
-    }
-
-    link_message(integer which, integer num, string msg, key id) {
-        manage_those_voices(num, msg);
-    }
-
-    // reset when we see changes to our notecard configuration.
-    changed(integer change) {
-        if (change & CHANGED_INVENTORY) {
-            llSleep(3.14159265358);  // delay to avoid interfering with upgrade.
-            state default;
-        }
-    }
-}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/zenmondos_mailbox_v0.4.lsl b/huffware/huffotronic_updater_freebie_v5.3/zenmondos_mailbox_v0.4.lsl
new file mode 100755 (executable)
index 0000000..4e6eb83
--- /dev/null
@@ -0,0 +1,276 @@
+
+// huffware script: zen mondo's mailbox, modified by fred huffhines.
+//
+// original attributions are below.
+//
+// my changes are licensed via:
+//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
+//   do not use it in objects without fully realizing you are implicitly accepting that license.
+//
+
+//////////////////////////////////////
+// ZenMondo's Mailbox by ZenMondo Wormser
+//
+// Displays Online Status, as well as accepting
+// notecard "mail" to be be delivered to owner.
+//
+// Cleans Up after itself, deletes non-notecards.
+//
+//
+// LICENSE:
+//
+//  This script is given for free, and may NOT be 
+//  resold or used in a commercial product.
+//  You may copy and distribute this script for free.
+//  When you redistribute or copy this script, you must
+//  do so with FULL PERMS (modify, copy, and transfer),
+//  and leave this notice intact.
+//
+//  You are free to modify this code, but any derivitive
+//  scripts must not be used in a commercial product or
+//  or sold, and must contain this license.  
+//
+//  This script is provided free for learning 
+//  purposes, take it apart, break it, fix it, 
+//  learn something.  If you come up with something 
+//  clever, share it.
+//
+//  Questions about codepoetry (scripting) can always be addressed
+//  to me, ZenMondo Wormser.
+//
+///////////////////////////////////////// 
+
+key online_query;
+
+key name_query;
+
+string user_name;
+
+
+//////////////
+// huffware script: auto-retire, by fred huffhines, version 2.5.
+// distributed under BSD-like license.
+//   !!  keep in mind that this code must be *copied* into another
+//   !!  script that you wish to add auto-retirement capability to.
+// when a script has auto_retire in it, it can be dropped into an
+// object and the most recent version of the script will destroy
+// all older versions.
+//
+// the version numbers are embedded into the script names themselves.
+// the notation for versions uses a letter 'v', followed by two numbers
+// in the form "major.minor".
+// major and minor versions are implicitly considered as a floating point
+// number that increases with each newer version of the script.  thus,
+// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
+// and "hazmap v3.2" is a more recent version.
+//
+// example usage of the auto-retirement script:
+//     default {
+//         state_entry() {
+//            auto_retire();  // make sure newest addition is only version of script.
+//        }
+//     }
+// this script is partly based on the self-upgrading scripts from markov brodsky
+// and jippen faddoul.
+//////////////
+auto_retire() {
+    string self = llGetScriptName();  // the name of this script.
+    list split = compute_basename_and_version(self);
+    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
+    string basename = llList2String(split, 0);  // script name with no version attached.
+    string version_string = llList2String(split, 1);  // the version found.
+    integer posn;
+    // find any scripts that match the basename.  they are variants of this script.
+    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
+        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
+        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
+            // found a basic match at least.
+            list inv_split = compute_basename_and_version(curr_script);
+            if (llGetListLength(inv_split) == 2) {
+                // see if this script is more ancient.
+                string inv_version_string = llList2String(inv_split, 1);  // the version found.
+                // must make sure that the retiring script is completely the identical basename;
+                // just matching in the front doesn't make it a relative.
+                if ( (llList2String(inv_split, 0) == basename)
+                    && ((float)inv_version_string < (float)version_string) ) {
+                    // remove script with same name from inventory that has inferior version.
+                    llRemoveInventory(curr_script);
+                }
+            }
+        }
+    }
+}
+//
+// separates the base script name and version number.  used by auto_retire.
+list compute_basename_and_version(string to_chop_up)
+{
+    // minimum script name is 2 characters plus a version.
+    integer space_v_posn;
+    // find the last useful space and 'v' combo.
+    for (space_v_posn = llStringLength(to_chop_up) - 3;
+        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
+        space_v_posn--) {
+        // look for space and v but do nothing else.
+    }
+    if (space_v_posn < 2) return [];  // no space found.
+    // now we zoom through the stuff after our beloved v character and find any evil
+    // space characters, which are most likely from SL having found a duplicate item
+    // name and not so helpfully renamed it for us.
+    integer indy;
+    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
+        if (llGetSubString(to_chop_up, indy, indy) == " ") {
+            // found one; zap it.  since we're going backwards we don't need to
+            // adjust the loop at all.
+            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
+        }
+    }
+    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
+    // ditch the space character for our numerical check.
+    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
+    // strip out a 'v' if there is one.
+    if (llGetSubString(chop_suffix, 0, 0) == "v")
+        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
+    // if valid floating point number and greater than zero, that works for our version.
+    string basename = to_chop_up;  // script name with no version attached.
+    if ((float)chop_suffix > 0.0) {
+        // this is a big success right here.
+        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
+        return [ basename, chop_suffix ];
+    }
+    // seems like we found nothing useful.
+    return [];
+}
+//
+//////////////
+
+
+default {
+    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
+    on_rez(integer parm) { state rerun; }
+}
+state rerun { state_entry() { state default; } }
+
+state real_default
+{
+    state_entry()
+    {
+        auto_retire();
+        llAllowInventoryDrop(TRUE);
+        name_query = llRequestAgentData(llGetOwner(), DATA_NAME);
+        llSetText("Setting Up, Ready in one minute.", <0,1,1>, 1.0);
+        llSetTimerEvent(60);
+        
+        
+    }
+
+    timer()
+    {
+        online_query = llRequestAgentData(llGetOwner(),DATA_ONLINE);          
+    }
+    
+    dataserver(key queryid, string data)
+    {
+        
+        if(queryid == name_query)
+        {
+            user_name = data;
+            //llSay(0, data + " " + user_name);
+        }
+        
+        if(queryid == online_query)
+        {
+            integer online = (integer) data;
+        
+            if(online)
+            {
+                llSetText(user_name + " is ONLINE\nDrop a NoteCard into me\nto Send " + user_name + " a message.", <0,1,0>, 1.0);
+                return;   
+            }
+        
+            else
+            {
+                llSetText(user_name + " is OFFLINE\nDrop a NoteCard into me\nto Send " + user_name + " a message.", <1,0,0>, 1.0);
+                return;
+            }
+       
+        }     
+    }
+    
+    changed(integer mask)
+    {
+        if(mask & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))
+        {
+            integer num_notes = llGetInventoryNumber(INVENTORY_NOTECARD);
+            
+            if(num_notes > 0)
+            {
+                string note_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
+                            
+                llSay(0, "Sending Notecard, '" + note_name +"' please stand by.");
+            
+                llGiveInventory(llGetOwner(), note_name);
+                
+                llInstantMessage(llGetOwner(), "A NoteCard has been sent to you: " + note_name);
+                llSay(0, "The Notecard, " + note_name + " has been sent. Thank you.");
+                
+            
+                llRemoveInventory(note_name);
+                
+                num_notes = llGetInventoryNumber(INVENTORY_NOTECARD);
+                
+                while(num_notes > 0) // They dropped more than one notecard. Clean it up
+                {   
+                    note_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
+                      
+                    llSay(0, "Deleting " + note_name + ". It was not submitted.  Try Dropping one note at a time.");
+                    
+                    llRemoveInventory(note_name);
+                    
+                    num_notes = llGetInventoryNumber(INVENTORY_NOTECARD);
+                    
+                }
+                
+            }
+            
+            else //Not a Notecard
+            {
+               //find out what was dropped and remove it.  
+                
+                
+                list inventory;
+                integer num_inv = llGetInventoryNumber(INVENTORY_ALL); // Should be 2
+                integer counter = 0;
+                while(counter < num_inv)
+                {
+                    inventory += [llGetInventoryName(INVENTORY_ALL, counter)];
+                    counter ++;   
+                }
+                
+                // WHat we expect to find
+                list this_script = [llGetScriptName()];
+                
+                //Delete this script (which belong in the inventory) from the list
+                integer index = llListFindList(inventory, this_script);
+                inventory = llDeleteSubList(inventory, index, index);
+                
+                
+                index = llGetListLength(inventory);
+                
+                
+                //Just in case they snuck in more than one inventory item
+                while (index >= 1)
+                {                
+                    llSay(0, "That was not a notecard. Removing " + llList2String(inventory, 0));
+                    llRemoveInventory(llList2String(inventory, 0));
+                    inventory = llDeleteSubList(inventory, 0, 0);
+                    index = llGetListLength(inventory);   
+                } 
+            }
+        }
+    }
+    
+    on_rez(integer start_param)
+    {
+        llResetScript();
+    }
+}
diff --git a/huffware/huffotronic_updater_freebie_v5.3/zenmondos_mailbox_v0.4.txt b/huffware/huffotronic_updater_freebie_v5.3/zenmondos_mailbox_v0.4.txt
deleted file mode 100755 (executable)
index 4e6eb83..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-
-// huffware script: zen mondo's mailbox, modified by fred huffhines.
-//
-// original attributions are below.
-//
-// my changes are licensed via:
-//   this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-//   do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-//////////////////////////////////////
-// ZenMondo's Mailbox by ZenMondo Wormser
-//
-// Displays Online Status, as well as accepting
-// notecard "mail" to be be delivered to owner.
-//
-// Cleans Up after itself, deletes non-notecards.
-//
-//
-// LICENSE:
-//
-//  This script is given for free, and may NOT be 
-//  resold or used in a commercial product.
-//  You may copy and distribute this script for free.
-//  When you redistribute or copy this script, you must
-//  do so with FULL PERMS (modify, copy, and transfer),
-//  and leave this notice intact.
-//
-//  You are free to modify this code, but any derivitive
-//  scripts must not be used in a commercial product or
-//  or sold, and must contain this license.  
-//
-//  This script is provided free for learning 
-//  purposes, take it apart, break it, fix it, 
-//  learn something.  If you come up with something 
-//  clever, share it.
-//
-//  Questions about codepoetry (scripting) can always be addressed
-//  to me, ZenMondo Wormser.
-//
-///////////////////////////////////////// 
-
-key online_query;
-
-key name_query;
-
-string user_name;
-
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry()
-    {
-        auto_retire();
-        llAllowInventoryDrop(TRUE);
-        name_query = llRequestAgentData(llGetOwner(), DATA_NAME);
-        llSetText("Setting Up, Ready in one minute.", <0,1,1>, 1.0);
-        llSetTimerEvent(60);
-        
-        
-    }
-
-    timer()
-    {
-        online_query = llRequestAgentData(llGetOwner(),DATA_ONLINE);          
-    }
-    
-    dataserver(key queryid, string data)
-    {
-        
-        if(queryid == name_query)
-        {
-            user_name = data;
-            //llSay(0, data + " " + user_name);
-        }
-        
-        if(queryid == online_query)
-        {
-            integer online = (integer) data;
-        
-            if(online)
-            {
-                llSetText(user_name + " is ONLINE\nDrop a NoteCard into me\nto Send " + user_name + " a message.", <0,1,0>, 1.0);
-                return;   
-            }
-        
-            else
-            {
-                llSetText(user_name + " is OFFLINE\nDrop a NoteCard into me\nto Send " + user_name + " a message.", <1,0,0>, 1.0);
-                return;
-            }
-       
-        }     
-    }
-    
-    changed(integer mask)
-    {
-        if(mask & (CHANGED_ALLOWED_DROP | CHANGED_INVENTORY))
-        {
-            integer num_notes = llGetInventoryNumber(INVENTORY_NOTECARD);
-            
-            if(num_notes > 0)
-            {
-                string note_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
-                            
-                llSay(0, "Sending Notecard, '" + note_name +"' please stand by.");
-            
-                llGiveInventory(llGetOwner(), note_name);
-                
-                llInstantMessage(llGetOwner(), "A NoteCard has been sent to you: " + note_name);
-                llSay(0, "The Notecard, " + note_name + " has been sent. Thank you.");
-                
-            
-                llRemoveInventory(note_name);
-                
-                num_notes = llGetInventoryNumber(INVENTORY_NOTECARD);
-                
-                while(num_notes > 0) // They dropped more than one notecard. Clean it up
-                {   
-                    note_name = llGetInventoryName(INVENTORY_NOTECARD, 0);
-                      
-                    llSay(0, "Deleting " + note_name + ". It was not submitted.  Try Dropping one note at a time.");
-                    
-                    llRemoveInventory(note_name);
-                    
-                    num_notes = llGetInventoryNumber(INVENTORY_NOTECARD);
-                    
-                }
-                
-            }
-            
-            else //Not a Notecard
-            {
-               //find out what was dropped and remove it.  
-                
-                
-                list inventory;
-                integer num_inv = llGetInventoryNumber(INVENTORY_ALL); // Should be 2
-                integer counter = 0;
-                while(counter < num_inv)
-                {
-                    inventory += [llGetInventoryName(INVENTORY_ALL, counter)];
-                    counter ++;   
-                }
-                
-                // WHat we expect to find
-                list this_script = [llGetScriptName()];
-                
-                //Delete this script (which belong in the inventory) from the list
-                integer index = llListFindList(inventory, this_script);
-                inventory = llDeleteSubList(inventory, index, index);
-                
-                
-                index = llGetListLength(inventory);
-                
-                
-                //Just in case they snuck in more than one inventory item
-                while (index >= 1)
-                {                
-                    llSay(0, "That was not a notecard. Removing " + llList2String(inventory, 0));
-                    llRemoveInventory(llList2String(inventory, 0));
-                    inventory = llDeleteSubList(inventory, 0, 0);
-                    index = llGetListLength(inventory);   
-                } 
-            }
-        }
-    }
-    
-    on_rez(integer start_param)
-    {
-        llResetScript();
-    }
-}
diff --git a/huffware/jaunting/jaunting_library_v15.9.lsl b/huffware/jaunting/jaunting_library_v15.9.lsl
deleted file mode 100644 (file)
index 6613cf3..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-
-// huffware script: jaunting library, by fred huffhines, released under GPL-v3 license.
-//
-// this script is a library of useful teleportation and movement calls.  it should be added
-// into an object along with other scripts that use the library.  the jaunting library
-// responds to linked messages as commands.
-// parts of this script are based on warpPos from "Teleporter Script v 3.0 by Asira Sakai",
-// which was found at the LSL wiki.
-//
-// this script is licensed by the GPL v3 which is documented at: http://www.gnu.org/licenses/gpl.html
-// do not use it in objects without fully realizing you are implicitly accepting that license.
-//
-
-// global constants...
-
-float PROXIMITY_REQUIRED = 0.1;
-    // how close we must be to the target location to call the jaunt done.
-    // we make this fairly low accuracy since we don't want jumps in space to immediately
-    // be counted as failures.
-
-// the most jumps the script will try to take.  the overall distance from the start
-// to the end can be 10 * MAXIMUM_JUMPS_PER_CALL meters.
-integer MAXIMUM_JUMPS_PER_CALL = 84;
-
-// global variables...
-
-vector last_posn;  // used to calculate jump distances.
-
-// jaunting library link message API...
-//////////////
-// do not redefine these constants.
-integer JAUNT_HUFFWARE_ID = 10008;
-    // the unique id within the huffware system for the jaunt script to
-    // accept commands on.  this is used in llMessageLinked as the num parameter.
-string HUFFWARE_PARM_SEPARATOR = "{~~~}";
-    // this pattern is an uncommon thing to see in text, so we use it to separate
-    // our commands in link messages.
-string HUFFWARE_ITEM_SEPARATOR = "{|||}";
-    // used to separate lists of items from each other when stored inside a parameter.
-    // this allows lists to be passed as single string parameters if needed.
-integer REPLY_DISTANCE = 100008;  // offset added to service's huffware id in reply IDs.
-// commands available via the jaunting library:
-string JAUNT_COMMAND = "#jaunt#";
-    // command used to tell jaunt script to move object.  pass a vector with the location.
-string FULL_STOP_COMMAND = "#fullstop#";
-    // command used to bring object to a halt.
-string REVERSE_VELOCITY_COMMAND = "#reverse#";
-    // makes the object reverse its velocity and travel back from whence it came.
-string SET_VELOCITY_COMMAND = "#setvelocity#";
-    // makes the velocity equal to the vector passed as the first parameter.
-string JAUNT_UP_COMMAND = "#jauntup#";
-string JAUNT_DOWN_COMMAND = "#jauntdown#";
-    // commands for height adjustment.  pass a float for number of meters to move.
-string JAUNT_LIST_COMMAND = "#jauntlist#";
-    // like regular jaunt, but expects a list of vectors as the first parameter; this list
-    // should be in the jaunter notecard format (separated by pipe characters).
-    // the second parameter, if any, should be 1 for forwards traversal and 0 for backwards.
-//////////////
-
-// returns what we consider to be safe to do in one big jump.
-float distance_safe_to_jaunt() { return (float)(MAXIMUM_JUMPS_PER_CALL - 4) * 10.0; }
-
-// tests whether the destination is safe for an object to enter.
-integer safe_for_entry(vector where)
-{
-    if (outside_of_sim(where)) {
-        // that's an obvious wrong idea; it tends to break us.
-        return FALSE;
-    }
-    return TRUE;
-}
-
-// helper function for warp_across_list.  this adds one jump vector to the
-// list of rules as long as the destination is interesting.
-list process_warp_item(vector next_jump)
-{
-//log_it("mem: " + (string)llGetFreeMemory());
-    // calculate the number of jumps needed.
-    integer jumps = (integer)(llVecDist(next_jump, last_posn) / 10.0) + 1;
-    last_posn = next_jump;  // record for next check.
-    // set up our list which we'll replicate.
-    list rules = [ PRIM_POSITION, next_jump ];
-    // Try and avoid stack/heap collisions.
-    if (jumps > MAXIMUM_JUMPS_PER_CALL - 1) jumps = MAXIMUM_JUMPS_PER_CALL;
-    // add the rules repeatedly to get the effective overall jump done.
-    integer count = 1;
-    while ( (count = count << 1) < jumps)
-        rules += rules;
-    // magnify the rule list before really adding it.  this gets us to the proper
-    // final number of jumps.
-    return rules + llList2List(rules, (count - jumps) << 1 - 2, count);
-}
-
-// originally based on warpPos from lsl wiki but drastically modified.
-// uses a set of transfer points instead of a single target.
-list warp_across_list(list full_journey, integer forwards)
-{
-    // make sure the list didn't run out.
-    if (llGetListLength(full_journey) == 0) return [];
-    if (forwards) {
-        // forwards traversal of the list.
-        vector next_jump = (vector)llList2String(full_journey, 0);
-        // shortcut the jumps if we're already there.
-        if (next_jump == llGetPos())
-            return warp_across_list(chop_list(full_journey, 1,
-                llGetListLength(full_journey) - 1), forwards);
-        // calculate our trajectory for the next jump and add in all subsequent jumps.
-        return process_warp_item(next_jump)
-            + warp_across_list(chop_list(full_journey, 1, llGetListLength(full_journey) - 1), forwards);
-    } else {
-        // reverse traversal of the list.
-        vector next_jump = (vector)llList2String(full_journey, llGetListLength(full_journey) - 1);
-        // shortcut the jumps if we're already there.
-        if (next_jump == llGetPos())
-            return warp_across_list(chop_list(full_journey, 0,
-                llGetListLength(full_journey) - 2), forwards);
-        // calculate our trajectory for the next jump and add in all subsequent jumps.
-        return process_warp_item(next_jump)
-            + warp_across_list(chop_list(full_journey, 0, llGetListLength(full_journey) - 2), forwards);
-    }
-}
-
-// the main function that performs the jaunting process.
-// now also supports adding a rotation into the mix to avoid paying the extra delay
-// cost of calling llSetRot.
-jaunt(list full_journey, integer forwards, string command_used,
-    integer use_rotation, rotation rot, integer reply_to_request)
-{
-//log_it("jaunt: fullj=" + (string)full_journey + " forew=" + (string)forwards);
-    // set up our global variables...
-    last_posn = llGetPos();
-    // calculate the trip and run it.
-    list rot_add;
-    if (use_rotation)
-        rot_add = [ PRIM_ROTATION, rot ];
-    llSetPrimitiveParams(warp_across_list(full_journey, forwards) + rot_add);
-    if (reply_to_request) {
-        // pick out the last target in the list based on the direction we're moving.
-        integer last_indy = 0;
-        if (forwards == TRUE) last_indy = llGetListLength(full_journey) - 1;
-        vector last_jump = (vector)llList2String(full_journey, last_indy);
-        // final judge of success here is how close we got to the target.
-        integer landed_there = (llVecDist(llGetPos(), last_jump) <= PROXIMITY_REQUIRED);
-        send_reply(LINK_THIS, [landed_there, llGetPos()], command_used);
-    }
-}
-
-//////////////
-
-// sets the object's speed to "new_velocity".
-// if "local_axis" is TRUE, then it will be relative to the object's
-// own local coordinates.
-set_velocity(vector new_velocity, integer local_axis)
-{
-    vector current_velocity = llGetVel();
-         
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    
-    new_velocity -= current_velocity;
-    new_velocity *= llGetMass();
-    
-    llApplyImpulse(new_velocity, local_axis);
-}
-
-// attempts to bring the object to a complete stop.
-full_stop()
-{
-    llSetForce(<0,0,0>, FALSE);
-    set_velocity(<0,0,0>, FALSE);
-}
-
-// sends an object back along its trajectory.
-reverse_velocity(integer local_axis)
-{
-    vector current_velocity = llGetVel();
-    if (local_axis) {
-        rotation rot = llGetRot();
-        current_velocity /= rot;  // undo the rotation.
-    }
-    vector new_velocity = -2 * current_velocity;
-    new_velocity *= llGetMass();
-    llApplyImpulse(new_velocity, local_axis);
-}
-
-// teleports to the new "location", if possible.  does not change object's phantom / physical
-// states.  this will do the jaunt in multiple steps if the distance from here to "location"
-// is too large.
-apportioned_jaunt(vector location, string command_used, integer use_rotation, rotation rot,
-    integer should_send_reply)
-{
-    if (!safe_for_entry(location)) {
-        // that's not good.  we should not allow the script to get broken.
-        if (should_send_reply)
-            send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-        return;
-    }
-    // go to position specified, by leapfrogs if too long.
-    integer chunk_of_jump;
-    integer MAX_CHUNKS = 200;  // multiplies the distance a single jaunt can cover.
-    for (chunk_of_jump = 0; chunk_of_jump < MAX_CHUNKS; chunk_of_jump++) {
-        vector interim_vec = location - llGetPos();
-        float jump_dist = llVecDist(llGetPos(), location);
-        integer reply_needed = TRUE;
-        if (jump_dist > distance_safe_to_jaunt()) {
-            // the entire distance cannot be jumped.  do the part of it that fits.
-            float proportion_can_do = distance_safe_to_jaunt() / jump_dist;
-            interim_vec *= proportion_can_do;
-            reply_needed = FALSE;  // don't reply when this is not full jump.
-        }
-        interim_vec += llGetPos();  // bias jump back to where we are.
-//log_it("jumping from " + (string)llGetPos() + " to " + (string)interim_vec);
-        jaunt([llGetPos(), interim_vec], TRUE, command_used, use_rotation, rot,
-            reply_needed && should_send_reply);
-        float dist_now = llVecDist(llGetPos(), interim_vec);
-        if (dist_now > PROXIMITY_REQUIRED) {
-//log_it("failed to make interim jump, dist left is " + (string)dist_now);
-            // bail out.  we failed to get as far as we thought we should.
-            chunk_of_jump = MAX_CHUNKS + 10;
-            if (!reply_needed) {
-                // we need to send the reply we hadn't sent yet.
-                if (should_send_reply)
-                    send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-            }
-        } else if (llVecDist(llGetPos(), location) <= PROXIMITY_REQUIRED) {
-            // leave loop for a different reason; we got there.
-            chunk_of_jump = MAX_CHUNKS + 10;
-            if (!reply_needed) {
-                // we need to send the reply we hadn't sent yet.
-                if (should_send_reply)
-                    send_reply(LINK_THIS, [TRUE, llGetPos()], command_used);
-            }
-        }
-    }
-}
-
-// the entire distance embodied in the list of targets.  this is a little smart,
-// in that if there's only one target, we assume we're going from "here" to that
-// one target.
-float total_jaunt_distance(list targets)
-{
-    if (!llGetListLength(targets)) return 0.0;
-    // add in "this" location if they omitted it.
-    if (llGetListLength(targets) < 2)
-        targets = [ llGetPos() ] + targets;
-    integer disindy;
-    float total_dist = 0.0;
-    vector prev = (vector)llList2String(targets, 0);
-    for (disindy = 1; disindy < llGetListLength(targets); disindy++) {
-        vector next = (vector)llList2String(targets, disindy);
-        total_dist += llVecDist(prev, next);
-        prev = next;
-    }
-    return total_dist;
-}
-
-// jaunts to a target via a set of intermediate locations.  can either go forwards
-// through the list or backwards.
-phantom_jaunt_to_list(list targets, integer forwards, string command_used,
-    integer use_rotation, rotation rot)
-{
-    vector final_loc;
-    if (forwards) final_loc = (vector)llList2String(targets, llGetListLength(targets) - 1);
-    else final_loc = (vector)llList2String(targets, 0);
-
-//hmmm: check each destination in list??
-    if (!safe_for_entry(final_loc)) {
-        // that's not good.  we should not allow the script to get broken.
-        send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-        return;
-    }
-    
-    // this turns off the physics property for the object, so that jaunt and
-    // llSetPos will still work.  this became necessary due to havok4.
-    integer original_phantomosity = llGetStatus(STATUS_PHANTOM);
-    integer original_physicality = llGetStatus(STATUS_PHYSICS);
-    if (original_physicality != FALSE) llSetStatus(STATUS_PHYSICS, FALSE);
-    if (original_phantomosity != TRUE) llSetStatus(STATUS_PHANTOM, TRUE);
-
-    integer send_reply_still = TRUE;  // true if we should send a reply when done.
-
-    // iterate through our list of targets and either we will jaunt to the next
-    // place directly or we will have to wrap a few destinations due to sim crossing.
-    while (llGetListLength(targets) > 0) {
-        vector next_loc;
-        if (forwards) next_loc = (vector)llList2String(targets, 0);
-        else next_loc = (vector)llList2String(targets, llGetListLength(targets) - 1);
-        if (outside_of_sim(next_loc)) {
-            log_it("bad jaunt path: first target is out of sim.");
-            send_reply(LINK_THIS, [FALSE, llGetPos()], command_used);
-            return;  // skip that badness.
-        }
-        
-        // check how much total distance we have in the path that's left.  if it's under our
-        // limit, then we'll just take it in one jump.
-        float total_dist = total_jaunt_distance(targets);
-
-        // if we're below the threshold, we'll just jump now.
-        integer already_jumped = FALSE;
-        if (total_dist < distance_safe_to_jaunt()) {
-            jaunt(targets, forwards, command_used, use_rotation, rot, TRUE);
-            targets = [];  // reset the list now.
-            send_reply_still = FALSE;  // we have already sent the reply in jaunt().
-            already_jumped = TRUE;  // don't do anything else.
-        }
-        if (!already_jumped) {
-            vector next_plus_1 = ZERO_VECTOR;  // default cannot fail our "is inside sim" check.
-            if (llGetListLength(targets) > 1) {
-                if (forwards) next_plus_1 = (vector)llList2String(targets, 1);
-                else next_plus_1 = (vector)llList2String(targets, llGetListLength(targets) - 2);
-            }
-            if (outside_of_sim(next_plus_1)) {
-//hmmm: eventually find all the negative ones in a row and do them in combo, rather than
-//      just giving up here and doing a jaunt to the rest..
-                jaunt(targets, forwards, command_used, use_rotation, rot, TRUE);
-                targets = [];  // reset the list now.
-                send_reply_still = FALSE;  // we have already sent the reply in jaunt().
-            } else {
-                // we've passed the negativity test, so we can at least jump to the next place.
-                
-                // zap the next location, since we're about to jump there.
-                integer zap_pos = 0;
-                if (!forwards) zap_pos = llGetListLength(targets) - 1;
-                targets = llDeleteSubList(targets, zap_pos, zap_pos);        
-        
-                // only bother jumping if we're not already there.
-                if (llVecDist(next_loc, llGetPos()) > PROXIMITY_REQUIRED) {
-                    apportioned_jaunt(next_loc, command_used, use_rotation, rot, FALSE);
-                }
-            }
-        }
-    }
-
-    if (send_reply_still) {
-        integer yippee = TRUE;  // assume we succeeded until we prove otherwise.
-        if (llVecDist(final_loc, llGetPos()) > PROXIMITY_REQUIRED)
-            yippee = FALSE;
-        send_reply(LINK_THIS, [yippee, llGetPos()], command_used);
-    }
-
-    // return to prior characteristics.
-    if (original_phantomosity != TRUE) llSetStatus(STATUS_PHANTOM, original_phantomosity);
-    if (original_physicality != FALSE) llSetStatus(STATUS_PHYSICS, original_physicality);
-}
-
-// implements our API for jumping around.
-handle_link_message(integer sender, integer huff_id, string msg, key id)
-{
-    // separate the list out
-    list parms = llParseString2List(id, [HUFFWARE_PARM_SEPARATOR], []);
-    if (msg == JAUNT_COMMAND) {
-        // use list to string to avoid non-conversions.
-        vector v = (vector)llList2String(parms, 0);
-        rotation rot = <0.0, 0.0, 0.0, 1.0>;
-        integer gave_rot = llGetListLength(parms) > 1;
-        if (gave_rot) rot = (rotation)llList2String(parms, 1);  // ooh, they gave us a rotational value also.
-//        log_it("gave rot? " + (string)gave_rot + " rot=" + (string)rot);
-        phantom_jaunt_to_list([llGetPos(), v], TRUE, msg, gave_rot, rot);
-    } else if (msg == FULL_STOP_COMMAND) {
-        full_stop();
-    } else if (msg == REVERSE_VELOCITY_COMMAND) {
-        reverse_velocity(FALSE);
-    } else if (msg == SET_VELOCITY_COMMAND) {            
-        vector v = (vector)llList2String(parms, 0);
-//log_it("jaunting lib received set velocity request for " + (string)v);
-        set_velocity(v, FALSE);
-    } else if (msg == JAUNT_UP_COMMAND) {
-        phantom_jaunt_to_list([ llGetPos(), llGetPos() + <0.0, 0.0, llList2Float(parms, 0)> ],
-            TRUE, msg, FALSE, ZERO_ROTATION);
-    } else if (msg == JAUNT_DOWN_COMMAND) {
-        phantom_jaunt_to_list([ llGetPos(), llGetPos() + <0.0, 0.0, -llList2Float(parms, 0)> ],
-            TRUE, msg, FALSE, ZERO_ROTATION);
-    } else if (msg == JAUNT_LIST_COMMAND) {
-        string destination_list = llList2String(parms, 0);
-        list targets = llParseString2List(destination_list, [HUFFWARE_ITEM_SEPARATOR], []);
-        destination_list = "";
-        integer forwards = TRUE;
-        // snag the directionality for the list, if specified.
-        if (llGetListLength(parms) > 1) forwards = llList2Integer(parms, 1);
-        rotation rot = <0.0, 0.0, 0.0, 1.0>;
-        integer gave_rot = llGetListLength(parms) > 2;
-        if (gave_rot) rot = llList2Rot(parms, 2);  // ooh, they gave us a rotational value also.        
-        phantom_jaunt_to_list(targets, forwards, msg, gave_rot, rot);
-        targets = [];
-    }
-}
-
-//////////////
-// from hufflets...
-
-integer debug_num = 0;
-
-// a debugging output method.  can be disabled entirely in one place.
-log_it(string to_say)
-{
-    debug_num++;
-    // tell this to the owner.    
-    llOwnerSay(llGetScriptName() + "[" + (string)debug_num + "] " + to_say);
-    // say this on open chat, but use an unusual channel.
-//    llSay(108, llGetScriptName() + "--" + (string)debug_num + ": " + to_say);
-}
-//////////////
-
-// a simple version of a reply for a command that has been executed.  the parameters
-// might contain an outcome or result of the operation that was requested.
-send_reply(integer destination, list parms, string command)
-{
-    llMessageLinked(destination, JAUNT_HUFFWARE_ID + REPLY_DISTANCE, command,
-        llDumpList2String(parms, HUFFWARE_PARM_SEPARATOR));
-}
-
-// returns TRUE if the value in "to_check" specifies a legal x or y value in a sim.
-integer valid_sim_value(float to_check)
-{
-    if (to_check < 0.0) return FALSE;
-    if (to_check >= 257.0) return FALSE;
-    return TRUE;
-}
-
-integer outside_of_sim(vector to_check)
-{
-    return !valid_sim_value(to_check.x) || !valid_sim_value(to_check.y);
-}
-
-///////////////
-
-// returns the portion of the list between start and end, but only if they are
-// valid compared with the list length.  an attempt to use negative start or
-// end values also returns a blank list.
-list chop_list(list to_chop, integer start, integer end)
-{
-    integer last_len = llGetListLength(to_chop) - 1;
-    if ( (start < 0) || (end < 0) || (start > last_len) || (end > last_len) ) return [];
-    return llList2List(to_chop, start, end);
-}
-
-//////////////
-
-//////////////
-// huffware script: auto-retire, by fred huffhines, version 2.5.
-// distributed under BSD-like license.
-//   !!  keep in mind that this code must be *copied* into another
-//   !!  script that you wish to add auto-retirement capability to.
-// when a script has auto_retire in it, it can be dropped into an
-// object and the most recent version of the script will destroy
-// all older versions.
-//
-// the version numbers are embedded into the script names themselves.
-// the notation for versions uses a letter 'v', followed by two numbers
-// in the form "major.minor".
-// major and minor versions are implicitly considered as a floating point
-// number that increases with each newer version of the script.  thus,
-// "hazmap v0.1" might be the first script in the "hazmap" script continuum,
-// and "hazmap v3.2" is a more recent version.
-//
-// example usage of the auto-retirement script:
-//     default {
-//         state_entry() {
-//            auto_retire();  // make sure newest addition is only version of script.
-//        }
-//     }
-// this script is partly based on the self-upgrading scripts from markov brodsky
-// and jippen faddoul.
-//////////////
-auto_retire() {
-    string self = llGetScriptName();  // the name of this script.
-    list split = compute_basename_and_version(self);
-    if (llGetListLength(split) != 2) return;  // nothing to do for this script.
-    string basename = llList2String(split, 0);  // script name with no version attached.
-    string version_string = llList2String(split, 1);  // the version found.
-    integer posn;
-    // find any scripts that match the basename.  they are variants of this script.
-    for (posn = llGetInventoryNumber(INVENTORY_SCRIPT) - 1; posn >= 0; posn--) {
-        string curr_script = llGetInventoryName(INVENTORY_SCRIPT, posn);
-        if ( (curr_script != self) && (llSubStringIndex(curr_script, basename) == 0) ) {
-            // found a basic match at least.
-            list inv_split = compute_basename_and_version(curr_script);
-            if (llGetListLength(inv_split) == 2) {
-                // see if this script is more ancient.
-                string inv_version_string = llList2String(inv_split, 1);  // the version found.
-                // must make sure that the retiring script is completely the identical basename;
-                // just matching in the front doesn't make it a relative.
-                if ( (llList2String(inv_split, 0) == basename)
-                    && ((float)inv_version_string < (float)version_string) ) {
-                    // remove script with same name from inventory that has inferior version.
-                    llRemoveInventory(curr_script);
-                }
-            }
-        }
-    }
-}
-//
-// separates the base script name and version number.  used by auto_retire.
-list compute_basename_and_version(string to_chop_up)
-{
-    // minimum script name is 2 characters plus a version.
-    integer space_v_posn;
-    // find the last useful space and 'v' combo.
-    for (space_v_posn = llStringLength(to_chop_up) - 3;
-        (space_v_posn >= 2) && (llGetSubString(to_chop_up, space_v_posn, space_v_posn + 1) != " v");
-        space_v_posn--) {
-        // look for space and v but do nothing else.
-    }
-    if (space_v_posn < 2) return [];  // no space found.
-    // now we zoom through the stuff after our beloved v character and find any evil
-    // space characters, which are most likely from SL having found a duplicate item
-    // name and not so helpfully renamed it for us.
-    integer indy;
-    for (indy = llStringLength(to_chop_up) - 1; indy > space_v_posn; indy--) {
-        if (llGetSubString(to_chop_up, indy, indy) == " ") {
-            // found one; zap it.  since we're going backwards we don't need to
-            // adjust the loop at all.
-            to_chop_up = llDeleteSubString(to_chop_up, indy, indy);
-        }
-    }
-    string full_suffix = llGetSubString(to_chop_up, space_v_posn, -1);
-    // ditch the space character for our numerical check.
-    string chop_suffix = llGetSubString(full_suffix, 1, llStringLength(full_suffix) - 1);
-    // strip out a 'v' if there is one.
-    if (llGetSubString(chop_suffix, 0, 0) == "v")
-        chop_suffix = llGetSubString(chop_suffix, 1, llStringLength(chop_suffix) - 1);
-    // if valid floating point number and greater than zero, that works for our version.
-    string basename = to_chop_up;  // script name with no version attached.
-    if ((float)chop_suffix > 0.0) {
-        // this is a big success right here.
-        basename = llGetSubString(to_chop_up, 0, -llStringLength(full_suffix) - 1);
-        return [ basename, chop_suffix ];
-    }
-    // seems like we found nothing useful.
-    return [];
-}
-//
-//////////////
-
-default {
-    state_entry() { if (llSubStringIndex(llGetObjectName(), "huffotronic") < 0) state real_default; }
-    on_rez(integer parm) { state rerun; }
-}
-state rerun { state_entry() { state default; } }
-
-state real_default
-{
-    state_entry() { auto_retire(); }
-    
-    link_message(integer sender, integer huff_id, string msg, key id) {
-        if (huff_id != JAUNT_HUFFWARE_ID) return;  // not our responsibility.
-        handle_link_message(sender, huff_id, msg, id);
-    }
-}
-
diff --git a/huffware/jaunting/readme.txt b/huffware/jaunting/readme.txt
deleted file mode 100644 (file)
index f60166d..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Jaunting is our term for teleporting around the grid.  The term jaunt comes
-from 'The Stars My Destination' by Alfred Bester and we refer to it in a
-similar context.
-
-The jaunting library script is the useful encapsulation of a variety of
-teleportation and movement control methods.  It is interfaced to via a
-huffware API for remote procedure calls.
-
-