diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 000000000..2c9ad09b9 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 54791cadb861b60da937bd38120160da +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/api.doctree b/.doctrees/api.doctree new file mode 100644 index 000000000..49cb090fc Binary files /dev/null and b/.doctrees/api.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.ActiveChoiceWorldSession.doctree b/.doctrees/api/iblrig.base_choice_world.ActiveChoiceWorldSession.doctree new file mode 100644 index 000000000..621b38fcc Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.ActiveChoiceWorldSession.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.doctree b/.doctrees/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.doctree new file mode 100644 index 000000000..aadf9db06 Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.BiasedChoiceWorldSession.doctree b/.doctrees/api/iblrig.base_choice_world.BiasedChoiceWorldSession.doctree new file mode 100644 index 000000000..abb7bfad1 Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.BiasedChoiceWorldSession.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.doctree b/.doctrees/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.doctree new file mode 100644 index 000000000..ce0d05950 Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.ChoiceWorldSession.doctree b/.doctrees/api/iblrig.base_choice_world.ChoiceWorldSession.doctree new file mode 100644 index 000000000..1645802c1 Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.ChoiceWorldSession.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.ChoiceWorldTrialData.doctree b/.doctrees/api/iblrig.base_choice_world.ChoiceWorldTrialData.doctree new file mode 100644 index 000000000..79c45784a Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.ChoiceWorldTrialData.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.HabituationChoiceWorldSession.doctree b/.doctrees/api/iblrig.base_choice_world.HabituationChoiceWorldSession.doctree new file mode 100644 index 000000000..1d4aac15d Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.HabituationChoiceWorldSession.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.doctree b/.doctrees/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.doctree new file mode 100644 index 000000000..5fad7a498 Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.TrainingChoiceWorldSession.doctree b/.doctrees/api/iblrig.base_choice_world.TrainingChoiceWorldSession.doctree new file mode 100644 index 000000000..9f6c8d86d Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.TrainingChoiceWorldSession.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.doctree b/.doctrees/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.doctree new file mode 100644 index 000000000..6201ece51 Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.doctree differ diff --git a/.doctrees/api/iblrig.base_choice_world.doctree b/.doctrees/api/iblrig.base_choice_world.doctree new file mode 100644 index 000000000..4e779a01a Binary files /dev/null and b/.doctrees/api/iblrig.base_choice_world.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.BaseSession.doctree b/.doctrees/api/iblrig.base_tasks.BaseSession.doctree new file mode 100644 index 000000000..f04635716 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.BaseSession.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.BonsaiRecordingMixin.doctree b/.doctrees/api/iblrig.base_tasks.BonsaiRecordingMixin.doctree new file mode 100644 index 000000000..60a1a14e0 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.BonsaiRecordingMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.doctree b/.doctrees/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.doctree new file mode 100644 index 000000000..da5a40ec0 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.BpodMixin.doctree b/.doctrees/api/iblrig.base_tasks.BpodMixin.doctree new file mode 100644 index 000000000..3732aa3e3 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.BpodMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.EmptySession.doctree b/.doctrees/api/iblrig.base_tasks.EmptySession.doctree new file mode 100644 index 000000000..cd078c9a2 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.EmptySession.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.Frame2TTLMixin.doctree b/.doctrees/api/iblrig.base_tasks.Frame2TTLMixin.doctree new file mode 100644 index 000000000..27ce8859c Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.Frame2TTLMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.HasBpod.doctree b/.doctrees/api/iblrig.base_tasks.HasBpod.doctree new file mode 100644 index 000000000..fe882e387 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.HasBpod.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.NetworkSession.doctree b/.doctrees/api/iblrig.base_tasks.NetworkSession.doctree new file mode 100644 index 000000000..590cd30fc Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.NetworkSession.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.OSCClient.doctree b/.doctrees/api/iblrig.base_tasks.OSCClient.doctree new file mode 100644 index 000000000..fdd39e373 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.OSCClient.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.RotaryEncoderMixin.doctree b/.doctrees/api/iblrig.base_tasks.RotaryEncoderMixin.doctree new file mode 100644 index 000000000..631605acb Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.RotaryEncoderMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.SoundMixin.doctree b/.doctrees/api/iblrig.base_tasks.SoundMixin.doctree new file mode 100644 index 000000000..817da3d67 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.SoundMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.SpontaneousSession.doctree b/.doctrees/api/iblrig.base_tasks.SpontaneousSession.doctree new file mode 100644 index 000000000..51e180f12 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.SpontaneousSession.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.ValveMixin.doctree b/.doctrees/api/iblrig.base_tasks.ValveMixin.doctree new file mode 100644 index 000000000..ed3902f7e Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.ValveMixin.doctree differ diff --git a/.doctrees/api/iblrig.base_tasks.doctree b/.doctrees/api/iblrig.base_tasks.doctree new file mode 100644 index 000000000..112d560b5 Binary files /dev/null and b/.doctrees/api/iblrig.base_tasks.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.compute_adaptive_reward_volume.doctree b/.doctrees/api/iblrig.choiceworld.compute_adaptive_reward_volume.doctree new file mode 100644 index 000000000..27894dd24 Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.compute_adaptive_reward_volume.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.contrasts_set.doctree b/.doctrees/api/iblrig.choiceworld.contrasts_set.doctree new file mode 100644 index 000000000..0dd715b1b Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.contrasts_set.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.doctree b/.doctrees/api/iblrig.choiceworld.doctree new file mode 100644 index 000000000..969f0d648 Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.draw_training_contrast.doctree b/.doctrees/api/iblrig.choiceworld.draw_training_contrast.doctree new file mode 100644 index 000000000..dfb223a54 Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.draw_training_contrast.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.get_subject_training_info.doctree b/.doctrees/api/iblrig.choiceworld.get_subject_training_info.doctree new file mode 100644 index 000000000..4cd38eb2a Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.get_subject_training_info.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.training_contrasts_probabilities.doctree b/.doctrees/api/iblrig.choiceworld.training_contrasts_probabilities.doctree new file mode 100644 index 000000000..d70cbd54a Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.training_contrasts_probabilities.doctree differ diff --git a/.doctrees/api/iblrig.choiceworld.training_phase_from_contrast_set.doctree b/.doctrees/api/iblrig.choiceworld.training_phase_from_contrast_set.doctree new file mode 100644 index 000000000..1d4cd0c37 Binary files /dev/null and b/.doctrees/api/iblrig.choiceworld.training_phase_from_contrast_set.doctree differ diff --git a/.doctrees/api/iblrig.commands.dir_path.doctree b/.doctrees/api/iblrig.commands.dir_path.doctree new file mode 100644 index 000000000..c7fb8f2e7 Binary files /dev/null and b/.doctrees/api/iblrig.commands.dir_path.doctree differ diff --git a/.doctrees/api/iblrig.commands.doctree b/.doctrees/api/iblrig.commands.doctree new file mode 100644 index 000000000..46d467df4 Binary files /dev/null and b/.doctrees/api/iblrig.commands.doctree differ diff --git a/.doctrees/api/iblrig.commands.flush.doctree b/.doctrees/api/iblrig.commands.flush.doctree new file mode 100644 index 000000000..21d2f7902 Binary files /dev/null and b/.doctrees/api/iblrig.commands.flush.doctree differ diff --git a/.doctrees/api/iblrig.commands.remove_local_sessions.doctree b/.doctrees/api/iblrig.commands.remove_local_sessions.doctree new file mode 100644 index 000000000..598e69778 Binary files /dev/null and b/.doctrees/api/iblrig.commands.remove_local_sessions.doctree differ diff --git a/.doctrees/api/iblrig.commands.transfer_data.doctree b/.doctrees/api/iblrig.commands.transfer_data.doctree new file mode 100644 index 000000000..3cbf7811a Binary files /dev/null and b/.doctrees/api/iblrig.commands.transfer_data.doctree differ diff --git a/.doctrees/api/iblrig.commands.transfer_data_cli.doctree b/.doctrees/api/iblrig.commands.transfer_data_cli.doctree new file mode 100644 index 000000000..2e2f3f2ae Binary files /dev/null and b/.doctrees/api/iblrig.commands.transfer_data_cli.doctree differ diff --git a/.doctrees/api/iblrig.commands.transfer_ephys_data_cli.doctree b/.doctrees/api/iblrig.commands.transfer_ephys_data_cli.doctree new file mode 100644 index 000000000..ba363a7b3 Binary files /dev/null and b/.doctrees/api/iblrig.commands.transfer_ephys_data_cli.doctree differ diff --git a/.doctrees/api/iblrig.commands.transfer_video_data_cli.doctree b/.doctrees/api/iblrig.commands.transfer_video_data_cli.doctree new file mode 100644 index 000000000..062107fbd Binary files /dev/null and b/.doctrees/api/iblrig.commands.transfer_video_data_cli.doctree differ diff --git a/.doctrees/api/iblrig.commands.view_session.doctree b/.doctrees/api/iblrig.commands.view_session.doctree new file mode 100644 index 000000000..5fa1e11cc Binary files /dev/null and b/.doctrees/api/iblrig.commands.view_session.doctree differ diff --git a/.doctrees/api/iblrig.constants.doctree b/.doctrees/api/iblrig.constants.doctree new file mode 100644 index 000000000..c02910cbe Binary files /dev/null and b/.doctrees/api/iblrig.constants.doctree differ diff --git a/.doctrees/api/iblrig.doctree b/.doctrees/api/iblrig.doctree new file mode 100644 index 000000000..435d624e1 Binary files /dev/null and b/.doctrees/api/iblrig.doctree differ diff --git a/.doctrees/api/iblrig.ephys.doctree b/.doctrees/api/iblrig.ephys.doctree new file mode 100644 index 000000000..1b7947f33 Binary files /dev/null and b/.doctrees/api/iblrig.ephys.doctree differ diff --git a/.doctrees/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.doctree b/.doctrees/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.doctree new file mode 100644 index 000000000..4549f1876 Binary files /dev/null and b/.doctrees/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.doctree differ diff --git a/.doctrees/api/iblrig.ephys.prepare_ephys_session.doctree b/.doctrees/api/iblrig.ephys.prepare_ephys_session.doctree new file mode 100644 index 000000000..6c84abedc Binary files /dev/null and b/.doctrees/api/iblrig.ephys.prepare_ephys_session.doctree differ diff --git a/.doctrees/api/iblrig.ephys.prepare_ephys_session_cmd.doctree b/.doctrees/api/iblrig.ephys.prepare_ephys_session_cmd.doctree new file mode 100644 index 000000000..34ac376be Binary files /dev/null and b/.doctrees/api/iblrig.ephys.prepare_ephys_session_cmd.doctree differ diff --git a/.doctrees/api/iblrig.frame2ttl.Frame2TTL.doctree b/.doctrees/api/iblrig.frame2ttl.Frame2TTL.doctree new file mode 100644 index 000000000..d7d53380b Binary files /dev/null and b/.doctrees/api/iblrig.frame2ttl.Frame2TTL.doctree differ diff --git a/.doctrees/api/iblrig.frame2ttl.doctree b/.doctrees/api/iblrig.frame2ttl.doctree new file mode 100644 index 000000000..60da86821 Binary files /dev/null and b/.doctrees/api/iblrig.frame2ttl.doctree differ diff --git a/.doctrees/api/iblrig.graphic.doctree b/.doctrees/api/iblrig.graphic.doctree new file mode 100644 index 000000000..9dae65491 Binary files /dev/null and b/.doctrees/api/iblrig.graphic.doctree differ diff --git a/.doctrees/api/iblrig.graphic.numinput.doctree b/.doctrees/api/iblrig.graphic.numinput.doctree new file mode 100644 index 000000000..10ee04e98 Binary files /dev/null and b/.doctrees/api/iblrig.graphic.numinput.doctree differ diff --git a/.doctrees/api/iblrig.gui.doctree b/.doctrees/api/iblrig.gui.doctree new file mode 100644 index 000000000..43836c9e4 Binary files /dev/null and b/.doctrees/api/iblrig.gui.doctree differ diff --git a/.doctrees/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.doctree b/.doctrees/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.doctree new file mode 100644 index 000000000..6177f9350 Binary files /dev/null and b/.doctrees/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.doctree differ diff --git a/.doctrees/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.doctree b/.doctrees/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.doctree new file mode 100644 index 000000000..fc026cb85 Binary files /dev/null and b/.doctrees/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.doctree differ diff --git a/.doctrees/api/iblrig.gui.frame2ttl.doctree b/.doctrees/api/iblrig.gui.frame2ttl.doctree new file mode 100644 index 000000000..055f741e2 Binary files /dev/null and b/.doctrees/api/iblrig.gui.frame2ttl.doctree differ diff --git a/.doctrees/api/iblrig.gui.resources_rc.doctree b/.doctrees/api/iblrig.gui.resources_rc.doctree new file mode 100644 index 000000000..d9beebc31 Binary files /dev/null and b/.doctrees/api/iblrig.gui.resources_rc.doctree differ diff --git a/.doctrees/api/iblrig.gui.resources_rc.qCleanupResources.doctree b/.doctrees/api/iblrig.gui.resources_rc.qCleanupResources.doctree new file mode 100644 index 000000000..abc7440f2 Binary files /dev/null and b/.doctrees/api/iblrig.gui.resources_rc.qCleanupResources.doctree differ diff --git a/.doctrees/api/iblrig.gui.resources_rc.qInitResources.doctree b/.doctrees/api/iblrig.gui.resources_rc.qInitResources.doctree new file mode 100644 index 000000000..15b2c4f13 Binary files /dev/null and b/.doctrees/api/iblrig.gui.resources_rc.qInitResources.doctree differ diff --git a/.doctrees/api/iblrig.gui.splash.Splash.doctree b/.doctrees/api/iblrig.gui.splash.Splash.doctree new file mode 100644 index 000000000..707451029 Binary files /dev/null and b/.doctrees/api/iblrig.gui.splash.Splash.doctree differ diff --git a/.doctrees/api/iblrig.gui.splash.doctree b/.doctrees/api/iblrig.gui.splash.doctree new file mode 100644 index 000000000..23fe528a6 Binary files /dev/null and b/.doctrees/api/iblrig.gui.splash.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_about.TabAbout.doctree b/.doctrees/api/iblrig.gui.tab_about.TabAbout.doctree new file mode 100644 index 000000000..7baa0e07b Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_about.TabAbout.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_about.doctree b/.doctrees/api/iblrig.gui.tab_about.doctree new file mode 100644 index 000000000..5ae123dc0 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_about.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_data.Column.doctree b/.doctrees/api/iblrig.gui.tab_data.Column.doctree new file mode 100644 index 000000000..1f24b088b Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_data.Column.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_data.DataItemDelegate.doctree b/.doctrees/api/iblrig.gui.tab_data.DataItemDelegate.doctree new file mode 100644 index 000000000..22b7c94f1 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_data.DataItemDelegate.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_data.DataWorker.doctree b/.doctrees/api/iblrig.gui.tab_data.DataWorker.doctree new file mode 100644 index 000000000..21708a825 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_data.DataWorker.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_data.TabData.doctree b/.doctrees/api/iblrig.gui.tab_data.TabData.doctree new file mode 100644 index 000000000..936796550 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_data.TabData.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_data.doctree b/.doctrees/api/iblrig.gui.tab_data.doctree new file mode 100644 index 000000000..97ea4bbdf Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_data.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_data.sizeof_fmt.doctree b/.doctrees/api/iblrig.gui.tab_data.sizeof_fmt.doctree new file mode 100644 index 000000000..4fe58b0bd Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_data.sizeof_fmt.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_docs.CustomWebEnginePage.doctree b/.doctrees/api/iblrig.gui.tab_docs.CustomWebEnginePage.doctree new file mode 100644 index 000000000..3ada56659 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_docs.CustomWebEnginePage.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_docs.TabDocs.doctree b/.doctrees/api/iblrig.gui.tab_docs.TabDocs.doctree new file mode 100644 index 000000000..f8b8c3fa4 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_docs.TabDocs.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_docs.doctree b/.doctrees/api/iblrig.gui.tab_docs.doctree new file mode 100644 index 000000000..8c48889f2 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_docs.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_log.TabLog.doctree b/.doctrees/api/iblrig.gui.tab_log.TabLog.doctree new file mode 100644 index 000000000..fb30c51e2 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_log.TabLog.doctree differ diff --git a/.doctrees/api/iblrig.gui.tab_log.doctree b/.doctrees/api/iblrig.gui.tab_log.doctree new file mode 100644 index 000000000..f4f930641 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tab_log.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.AlyxObject.doctree b/.doctrees/api/iblrig.gui.tools.AlyxObject.doctree new file mode 100644 index 000000000..a5977858c Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.AlyxObject.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.DataFrameTableModel.doctree b/.doctrees/api/iblrig.gui.tools.DataFrameTableModel.doctree new file mode 100644 index 000000000..c4dc80b41 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.DataFrameTableModel.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.DiskSpaceIndicator.doctree b/.doctrees/api/iblrig.gui.tools.DiskSpaceIndicator.doctree new file mode 100644 index 000000000..a39f88eba Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.DiskSpaceIndicator.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.LineEditAlyxUser.doctree b/.doctrees/api/iblrig.gui.tools.LineEditAlyxUser.doctree new file mode 100644 index 000000000..7e22a65dd Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.LineEditAlyxUser.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.RemoteDevicesItemModel.doctree b/.doctrees/api/iblrig.gui.tools.RemoteDevicesItemModel.doctree new file mode 100644 index 000000000..848808f8e Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.RemoteDevicesItemModel.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.RemoteDevicesListView.doctree b/.doctrees/api/iblrig.gui.tools.RemoteDevicesListView.doctree new file mode 100644 index 000000000..eae496dcb Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.RemoteDevicesListView.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.StatefulButton.doctree b/.doctrees/api/iblrig.gui.tools.StatefulButton.doctree new file mode 100644 index 000000000..f02191616 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.StatefulButton.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.Worker.doctree b/.doctrees/api/iblrig.gui.tools.Worker.doctree new file mode 100644 index 000000000..255baf406 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.Worker.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.WorkerSignals.doctree b/.doctrees/api/iblrig.gui.tools.WorkerSignals.doctree new file mode 100644 index 000000000..8b641b088 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.WorkerSignals.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.convert_uis.doctree b/.doctrees/api/iblrig.gui.tools.convert_uis.doctree new file mode 100644 index 000000000..afb3047e4 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.convert_uis.doctree differ diff --git a/.doctrees/api/iblrig.gui.tools.doctree b/.doctrees/api/iblrig.gui.tools.doctree new file mode 100644 index 000000000..0a7d3bc13 Binary files /dev/null and b/.doctrees/api/iblrig.gui.tools.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.doctree b/.doctrees/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.doctree new file mode 100644 index 000000000..a7f2c9893 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_frame2ttl.doctree b/.doctrees/api/iblrig.gui.ui_frame2ttl.doctree new file mode 100644 index 000000000..8ec649212 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_frame2ttl.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_login.Ui_login.doctree b/.doctrees/api/iblrig.gui.ui_login.Ui_login.doctree new file mode 100644 index 000000000..4e255fce7 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_login.Ui_login.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_login.doctree b/.doctrees/api/iblrig.gui.ui_login.doctree new file mode 100644 index 000000000..3fc91b54c Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_login.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_splash.Ui_splash.doctree b/.doctrees/api/iblrig.gui.ui_splash.Ui_splash.doctree new file mode 100644 index 000000000..74d2febc5 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_splash.Ui_splash.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_splash.doctree b/.doctrees/api/iblrig.gui.ui_splash.doctree new file mode 100644 index 000000000..53aeea512 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_splash.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_about.Ui_TabAbout.doctree b/.doctrees/api/iblrig.gui.ui_tab_about.Ui_TabAbout.doctree new file mode 100644 index 000000000..c117be454 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_about.Ui_TabAbout.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_about.doctree b/.doctrees/api/iblrig.gui.ui_tab_about.doctree new file mode 100644 index 000000000..3534a6d69 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_about.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_data.Ui_TabData.doctree b/.doctrees/api/iblrig.gui.ui_tab_data.Ui_TabData.doctree new file mode 100644 index 000000000..c8e22ad81 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_data.Ui_TabData.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_data.doctree b/.doctrees/api/iblrig.gui.ui_tab_data.doctree new file mode 100644 index 000000000..6b7d9c307 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_data.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.doctree b/.doctrees/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.doctree new file mode 100644 index 000000000..c0a69e1c0 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_docs.doctree b/.doctrees/api/iblrig.gui.ui_tab_docs.doctree new file mode 100644 index 000000000..a92c67a7b Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_docs.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_log.Ui_TabLog.doctree b/.doctrees/api/iblrig.gui.ui_tab_log.Ui_TabLog.doctree new file mode 100644 index 000000000..ce8d80057 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_log.Ui_TabLog.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_log.doctree b/.doctrees/api/iblrig.gui.ui_tab_log.doctree new file mode 100644 index 000000000..e33a41d89 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_log.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_session.Ui_tabSession.doctree b/.doctrees/api/iblrig.gui.ui_tab_session.Ui_tabSession.doctree new file mode 100644 index 000000000..060637292 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_session.Ui_tabSession.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_tab_session.doctree b/.doctrees/api/iblrig.gui.ui_tab_session.doctree new file mode 100644 index 000000000..7332b5009 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_tab_session.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_update.Ui_update.doctree b/.doctrees/api/iblrig.gui.ui_update.Ui_update.doctree new file mode 100644 index 000000000..c468e2a6a Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_update.Ui_update.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_update.doctree b/.doctrees/api/iblrig.gui.ui_update.doctree new file mode 100644 index 000000000..126ed5687 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_update.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_validation.Ui_validation.doctree b/.doctrees/api/iblrig.gui.ui_validation.Ui_validation.doctree new file mode 100644 index 000000000..62d4b0af6 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_validation.Ui_validation.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_validation.doctree b/.doctrees/api/iblrig.gui.ui_validation.doctree new file mode 100644 index 000000000..f27d6584a Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_validation.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_valve.Ui_valve.doctree b/.doctrees/api/iblrig.gui.ui_valve.Ui_valve.doctree new file mode 100644 index 000000000..da00507fc Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_valve.Ui_valve.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_valve.doctree b/.doctrees/api/iblrig.gui.ui_valve.doctree new file mode 100644 index 000000000..5cf95e0cf Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_valve.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_wizard.Ui_wizard.doctree b/.doctrees/api/iblrig.gui.ui_wizard.Ui_wizard.doctree new file mode 100644 index 000000000..c321a8f12 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_wizard.Ui_wizard.doctree differ diff --git a/.doctrees/api/iblrig.gui.ui_wizard.doctree b/.doctrees/api/iblrig.gui.ui_wizard.doctree new file mode 100644 index 000000000..51f4a2634 Binary files /dev/null and b/.doctrees/api/iblrig.gui.ui_wizard.doctree differ diff --git a/.doctrees/api/iblrig.gui.validation.StatusItem.doctree b/.doctrees/api/iblrig.gui.validation.StatusItem.doctree new file mode 100644 index 000000000..f3eba7355 Binary files /dev/null and b/.doctrees/api/iblrig.gui.validation.StatusItem.doctree differ diff --git a/.doctrees/api/iblrig.gui.validation.SystemValidationDialog.doctree b/.doctrees/api/iblrig.gui.validation.SystemValidationDialog.doctree new file mode 100644 index 000000000..f28f9e017 Binary files /dev/null and b/.doctrees/api/iblrig.gui.validation.SystemValidationDialog.doctree differ diff --git a/.doctrees/api/iblrig.gui.validation.ValidatorItem.doctree b/.doctrees/api/iblrig.gui.validation.ValidatorItem.doctree new file mode 100644 index 000000000..05cd4888d Binary files /dev/null and b/.doctrees/api/iblrig.gui.validation.ValidatorItem.doctree differ diff --git a/.doctrees/api/iblrig.gui.validation.doctree b/.doctrees/api/iblrig.gui.validation.doctree new file mode 100644 index 000000000..4f410b4b6 Binary files /dev/null and b/.doctrees/api/iblrig.gui.validation.doctree differ diff --git a/.doctrees/api/iblrig.gui.valve.CalibrationPlot.doctree b/.doctrees/api/iblrig.gui.valve.CalibrationPlot.doctree new file mode 100644 index 000000000..43b970529 Binary files /dev/null and b/.doctrees/api/iblrig.gui.valve.CalibrationPlot.doctree differ diff --git a/.doctrees/api/iblrig.gui.valve.ValveCalibrationDialog.doctree b/.doctrees/api/iblrig.gui.valve.ValveCalibrationDialog.doctree new file mode 100644 index 000000000..2edf4118e Binary files /dev/null and b/.doctrees/api/iblrig.gui.valve.ValveCalibrationDialog.doctree differ diff --git a/.doctrees/api/iblrig.gui.valve.doctree b/.doctrees/api/iblrig.gui.valve.doctree new file mode 100644 index 000000000..29cd017cc Binary files /dev/null and b/.doctrees/api/iblrig.gui.valve.doctree differ diff --git a/.doctrees/api/iblrig.gui.wizard.LoginWindow.doctree b/.doctrees/api/iblrig.gui.wizard.LoginWindow.doctree new file mode 100644 index 000000000..e28b5c259 Binary files /dev/null and b/.doctrees/api/iblrig.gui.wizard.LoginWindow.doctree differ diff --git a/.doctrees/api/iblrig.gui.wizard.RigWizard.doctree b/.doctrees/api/iblrig.gui.wizard.RigWizard.doctree new file mode 100644 index 000000000..c7c2de3e1 Binary files /dev/null and b/.doctrees/api/iblrig.gui.wizard.RigWizard.doctree differ diff --git a/.doctrees/api/iblrig.gui.wizard.RigWizardModel.doctree b/.doctrees/api/iblrig.gui.wizard.RigWizardModel.doctree new file mode 100644 index 000000000..847e8781c Binary files /dev/null and b/.doctrees/api/iblrig.gui.wizard.RigWizardModel.doctree differ diff --git a/.doctrees/api/iblrig.gui.wizard.UpdateNotice.doctree b/.doctrees/api/iblrig.gui.wizard.UpdateNotice.doctree new file mode 100644 index 000000000..8bc7c7f4a Binary files /dev/null and b/.doctrees/api/iblrig.gui.wizard.UpdateNotice.doctree differ diff --git a/.doctrees/api/iblrig.gui.wizard.doctree b/.doctrees/api/iblrig.gui.wizard.doctree new file mode 100644 index 000000000..12858a07a Binary files /dev/null and b/.doctrees/api/iblrig.gui.wizard.doctree differ diff --git a/.doctrees/api/iblrig.gui.wizard.main.doctree b/.doctrees/api/iblrig.gui.wizard.main.doctree new file mode 100644 index 000000000..1a7629b15 Binary files /dev/null and b/.doctrees/api/iblrig.gui.wizard.main.doctree differ diff --git a/.doctrees/api/iblrig.hardware.Bpod.doctree b/.doctrees/api/iblrig.hardware.Bpod.doctree new file mode 100644 index 000000000..e61a73787 Binary files /dev/null and b/.doctrees/api/iblrig.hardware.Bpod.doctree differ diff --git a/.doctrees/api/iblrig.hardware.MyRotaryEncoder.doctree b/.doctrees/api/iblrig.hardware.MyRotaryEncoder.doctree new file mode 100644 index 000000000..956b8b471 Binary files /dev/null and b/.doctrees/api/iblrig.hardware.MyRotaryEncoder.doctree differ diff --git a/.doctrees/api/iblrig.hardware.SOFTCODE.doctree b/.doctrees/api/iblrig.hardware.SOFTCODE.doctree new file mode 100644 index 000000000..2fc67440d Binary files /dev/null and b/.doctrees/api/iblrig.hardware.SOFTCODE.doctree differ diff --git a/.doctrees/api/iblrig.hardware.doctree b/.doctrees/api/iblrig.hardware.doctree new file mode 100644 index 000000000..329881a8c Binary files /dev/null and b/.doctrees/api/iblrig.hardware.doctree differ diff --git a/.doctrees/api/iblrig.hardware.restart_com_port.doctree b/.doctrees/api/iblrig.hardware.restart_com_port.doctree new file mode 100644 index 000000000..380774fde Binary files /dev/null and b/.doctrees/api/iblrig.hardware.restart_com_port.doctree differ diff --git a/.doctrees/api/iblrig.hardware.sound_device_factory.doctree b/.doctrees/api/iblrig.hardware.sound_device_factory.doctree new file mode 100644 index 000000000..cde8b32c9 Binary files /dev/null and b/.doctrees/api/iblrig.hardware.sound_device_factory.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.Result.doctree b/.doctrees/api/iblrig.hardware_validation.Result.doctree new file mode 100644 index 000000000..e951e39fd Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.Result.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.Status.doctree b/.doctrees/api/iblrig.hardware_validation.Status.doctree new file mode 100644 index 000000000..2b1c5ae5f Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.Status.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidateHardwareError.doctree b/.doctrees/api/iblrig.hardware_validation.ValidateHardwareError.doctree new file mode 100644 index 000000000..39cc322e7 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidateHardwareError.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.Validator.doctree b/.doctrees/api/iblrig.hardware_validation.Validator.doctree new file mode 100644 index 000000000..e1bda58b3 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.Validator.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorAlyx.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorAlyx.doctree new file mode 100644 index 000000000..f4c87cef2 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorAlyx.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorAmbientModule.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorAmbientModule.doctree new file mode 100644 index 000000000..89f7f8958 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorAmbientModule.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorBpod.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorBpod.doctree new file mode 100644 index 000000000..7b247be6f Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorBpod.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorCamera.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorCamera.doctree new file mode 100644 index 000000000..8ec687cdd Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorCamera.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorFrame2TTL.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorFrame2TTL.doctree new file mode 100644 index 000000000..f23862672 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorFrame2TTL.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorGit.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorGit.doctree new file mode 100644 index 000000000..39ace7e85 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorGit.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorMic.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorMic.doctree new file mode 100644 index 000000000..95e8aaeea Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorMic.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.doctree new file mode 100644 index 000000000..f58866c33 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorSerial.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorSerial.doctree new file mode 100644 index 000000000..f1e7f5e33 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorSerial.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorSound.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorSound.doctree new file mode 100644 index 000000000..28475809c Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorSound.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.ValidatorValve.doctree b/.doctrees/api/iblrig.hardware_validation.ValidatorValve.doctree new file mode 100644 index 000000000..40a059d04 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.ValidatorValve.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.doctree b/.doctrees/api/iblrig.hardware_validation.doctree new file mode 100644 index 000000000..5750a19f6 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.get_all_validators.doctree b/.doctrees/api/iblrig.hardware_validation.get_all_validators.doctree new file mode 100644 index 000000000..5855ac123 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.get_all_validators.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.run_all_validators.doctree b/.doctrees/api/iblrig.hardware_validation.run_all_validators.doctree new file mode 100644 index 000000000..e5b07e60b Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.run_all_validators.doctree differ diff --git a/.doctrees/api/iblrig.hardware_validation.run_all_validators_cli.doctree b/.doctrees/api/iblrig.hardware_validation.run_all_validators_cli.doctree new file mode 100644 index 000000000..98c672e89 Binary files /dev/null and b/.doctrees/api/iblrig.hardware_validation.run_all_validators_cli.doctree differ diff --git a/.doctrees/api/iblrig.hifi.HiFi.doctree b/.doctrees/api/iblrig.hifi.HiFi.doctree new file mode 100644 index 000000000..c5fbf1654 Binary files /dev/null and b/.doctrees/api/iblrig.hifi.HiFi.doctree differ diff --git a/.doctrees/api/iblrig.hifi.HiFiException.doctree b/.doctrees/api/iblrig.hifi.HiFiException.doctree new file mode 100644 index 000000000..3adf25cf6 Binary files /dev/null and b/.doctrees/api/iblrig.hifi.HiFiException.doctree differ diff --git a/.doctrees/api/iblrig.hifi.doctree b/.doctrees/api/iblrig.hifi.doctree new file mode 100644 index 000000000..c0fab4b7c Binary files /dev/null and b/.doctrees/api/iblrig.hifi.doctree differ diff --git a/.doctrees/api/iblrig.misc.doctree b/.doctrees/api/iblrig.misc.doctree new file mode 100644 index 000000000..c49ff9870 Binary files /dev/null and b/.doctrees/api/iblrig.misc.doctree differ diff --git a/.doctrees/api/iblrig.misc.draw_contrast.doctree b/.doctrees/api/iblrig.misc.draw_contrast.doctree new file mode 100644 index 000000000..a396d7511 Binary files /dev/null and b/.doctrees/api/iblrig.misc.draw_contrast.doctree differ diff --git a/.doctrees/api/iblrig.misc.get_biased_probs.doctree b/.doctrees/api/iblrig.misc.get_biased_probs.doctree new file mode 100644 index 000000000..523f0a8a8 Binary files /dev/null and b/.doctrees/api/iblrig.misc.get_biased_probs.doctree differ diff --git a/.doctrees/api/iblrig.misc.get_port_events.doctree b/.doctrees/api/iblrig.misc.get_port_events.doctree new file mode 100644 index 000000000..6e29179cb Binary files /dev/null and b/.doctrees/api/iblrig.misc.get_port_events.doctree differ diff --git a/.doctrees/api/iblrig.misc.get_session_path.doctree b/.doctrees/api/iblrig.misc.get_session_path.doctree new file mode 100644 index 000000000..0ef5865f3 Binary files /dev/null and b/.doctrees/api/iblrig.misc.get_session_path.doctree differ diff --git a/.doctrees/api/iblrig.misc.get_task_argument_parser.doctree b/.doctrees/api/iblrig.misc.get_task_argument_parser.doctree new file mode 100644 index 000000000..3f0459381 Binary files /dev/null and b/.doctrees/api/iblrig.misc.get_task_argument_parser.doctree differ diff --git a/.doctrees/api/iblrig.misc.get_task_arguments.doctree b/.doctrees/api/iblrig.misc.get_task_arguments.doctree new file mode 100644 index 000000000..fd3d7164d Binary files /dev/null and b/.doctrees/api/iblrig.misc.get_task_arguments.doctree differ diff --git a/.doctrees/api/iblrig.misc.online_std.doctree b/.doctrees/api/iblrig.misc.online_std.doctree new file mode 100644 index 000000000..3c85add3c Binary files /dev/null and b/.doctrees/api/iblrig.misc.online_std.doctree differ diff --git a/.doctrees/api/iblrig.misc.truncated_exponential.doctree b/.doctrees/api/iblrig.misc.truncated_exponential.doctree new file mode 100644 index 000000000..dd2f1270d Binary files /dev/null and b/.doctrees/api/iblrig.misc.truncated_exponential.doctree differ diff --git a/.doctrees/api/iblrig.net.Auxiliaries.doctree b/.doctrees/api/iblrig.net.Auxiliaries.doctree new file mode 100644 index 000000000..99731e8f0 Binary files /dev/null and b/.doctrees/api/iblrig.net.Auxiliaries.doctree differ diff --git a/.doctrees/api/iblrig.net.ExpInfo.doctree b/.doctrees/api/iblrig.net.ExpInfo.doctree new file mode 100644 index 000000000..aa202bd44 Binary files /dev/null and b/.doctrees/api/iblrig.net.ExpInfo.doctree differ diff --git a/.doctrees/api/iblrig.net.check_uri_match.doctree b/.doctrees/api/iblrig.net.check_uri_match.doctree new file mode 100644 index 000000000..90ba1df78 Binary files /dev/null and b/.doctrees/api/iblrig.net.check_uri_match.doctree differ diff --git a/.doctrees/api/iblrig.net.doctree b/.doctrees/api/iblrig.net.doctree new file mode 100644 index 000000000..8257f0217 Binary files /dev/null and b/.doctrees/api/iblrig.net.doctree differ diff --git a/.doctrees/api/iblrig.net.get_remote_devices.doctree b/.doctrees/api/iblrig.net.get_remote_devices.doctree new file mode 100644 index 000000000..b57bdef4f Binary files /dev/null and b/.doctrees/api/iblrig.net.get_remote_devices.doctree differ diff --git a/.doctrees/api/iblrig.net.get_remote_devices_file.doctree b/.doctrees/api/iblrig.net.get_remote_devices_file.doctree new file mode 100644 index 000000000..f725cdb62 Binary files /dev/null and b/.doctrees/api/iblrig.net.get_remote_devices_file.doctree differ diff --git a/.doctrees/api/iblrig.net.get_server_communicator.doctree b/.doctrees/api/iblrig.net.get_server_communicator.doctree new file mode 100644 index 000000000..e0f4892d3 Binary files /dev/null and b/.doctrees/api/iblrig.net.get_server_communicator.doctree differ diff --git a/.doctrees/api/iblrig.net.install_alyx_token.doctree b/.doctrees/api/iblrig.net.install_alyx_token.doctree new file mode 100644 index 000000000..26296e04d Binary files /dev/null and b/.doctrees/api/iblrig.net.install_alyx_token.doctree differ diff --git a/.doctrees/api/iblrig.net.read_stdin.doctree b/.doctrees/api/iblrig.net.read_stdin.doctree new file mode 100644 index 000000000..477e7e8bf Binary files /dev/null and b/.doctrees/api/iblrig.net.read_stdin.doctree differ diff --git a/.doctrees/api/iblrig.net.update_alyx_token.doctree b/.doctrees/api/iblrig.net.update_alyx_token.doctree new file mode 100644 index 000000000..39ebfa5a9 Binary files /dev/null and b/.doctrees/api/iblrig.net.update_alyx_token.doctree differ diff --git a/.doctrees/api/iblrig.online_plots.DataModel.doctree b/.doctrees/api/iblrig.online_plots.DataModel.doctree new file mode 100644 index 000000000..3828b3e9e Binary files /dev/null and b/.doctrees/api/iblrig.online_plots.DataModel.doctree differ diff --git a/.doctrees/api/iblrig.online_plots.OnlinePlots.doctree b/.doctrees/api/iblrig.online_plots.OnlinePlots.doctree new file mode 100644 index 000000000..6f8e0723d Binary files /dev/null and b/.doctrees/api/iblrig.online_plots.OnlinePlots.doctree differ diff --git a/.doctrees/api/iblrig.online_plots.doctree b/.doctrees/api/iblrig.online_plots.doctree new file mode 100644 index 000000000..5cca1a41f Binary files /dev/null and b/.doctrees/api/iblrig.online_plots.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.create_bonsai_layout_from_template.doctree b/.doctrees/api/iblrig.path_helper.create_bonsai_layout_from_template.doctree new file mode 100644 index 000000000..e19da789e Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.create_bonsai_layout_from_template.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.doctree b/.doctrees/api/iblrig.path_helper.doctree new file mode 100644 index 000000000..946c75327 Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.get_commit_hash.doctree b/.doctrees/api/iblrig.path_helper.get_commit_hash.doctree new file mode 100644 index 000000000..05a9ee402 Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.get_commit_hash.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.get_local_and_remote_paths.doctree b/.doctrees/api/iblrig.path_helper.get_local_and_remote_paths.doctree new file mode 100644 index 000000000..0be08fd6d Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.get_local_and_remote_paths.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.iterate_collection.doctree b/.doctrees/api/iblrig.path_helper.iterate_collection.doctree new file mode 100644 index 000000000..3633b3ec3 Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.iterate_collection.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.iterate_previous_sessions.doctree b/.doctrees/api/iblrig.path_helper.iterate_previous_sessions.doctree new file mode 100644 index 000000000..9ccc5bf2e Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.iterate_previous_sessions.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.load_pydantic_yaml.doctree b/.doctrees/api/iblrig.path_helper.load_pydantic_yaml.doctree new file mode 100644 index 000000000..664fd64e0 Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.load_pydantic_yaml.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.patch_settings.doctree b/.doctrees/api/iblrig.path_helper.patch_settings.doctree new file mode 100644 index 000000000..104bd757a Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.patch_settings.doctree differ diff --git a/.doctrees/api/iblrig.path_helper.save_pydantic_yaml.doctree b/.doctrees/api/iblrig.path_helper.save_pydantic_yaml.doctree new file mode 100644 index 000000000..c0fdd5b5c Binary files /dev/null and b/.doctrees/api/iblrig.path_helper.save_pydantic_yaml.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.BunchModel.doctree b/.doctrees/api/iblrig.pydantic_definitions.BunchModel.doctree new file mode 100644 index 000000000..7b575fa56 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.BunchModel.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.ExistingFilePath.doctree b/.doctrees/api/iblrig.pydantic_definitions.ExistingFilePath.doctree new file mode 100644 index 000000000..9d3578f42 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.ExistingFilePath.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettings.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettings.doctree new file mode 100644 index 000000000..65f1399be Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettings.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsBpod.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsBpod.doctree new file mode 100644 index 000000000..36a971b51 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsBpod.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsCamera.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsCamera.doctree new file mode 100644 index 000000000..d11a4c7fa Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsCamera.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.doctree new file mode 100644 index 000000000..4dd72a076 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.doctree new file mode 100644 index 000000000..23e24e19d Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.doctree new file mode 100644 index 000000000..4745a0ac3 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.doctree new file mode 100644 index 000000000..f162113ea Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsScale.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsScale.doctree new file mode 100644 index 000000000..0165f2526 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsScale.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsScreen.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsScreen.doctree new file mode 100644 index 000000000..c5a6b8db7 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsScreen.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsSound.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsSound.doctree new file mode 100644 index 000000000..b85db3f0d Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsSound.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsValve.doctree b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsValve.doctree new file mode 100644 index 000000000..739ef419b Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.HardwareSettingsValve.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.RigSettings.doctree b/.doctrees/api/iblrig.pydantic_definitions.RigSettings.doctree new file mode 100644 index 000000000..e3fd88fd4 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.RigSettings.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.TrialDataModel.doctree b/.doctrees/api/iblrig.pydantic_definitions.TrialDataModel.doctree new file mode 100644 index 000000000..db9e1c4b7 Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.TrialDataModel.doctree differ diff --git a/.doctrees/api/iblrig.pydantic_definitions.doctree b/.doctrees/api/iblrig.pydantic_definitions.doctree new file mode 100644 index 000000000..af311de5f Binary files /dev/null and b/.doctrees/api/iblrig.pydantic_definitions.doctree differ diff --git a/.doctrees/api/iblrig.raw_data_loaders.doctree b/.doctrees/api/iblrig.raw_data_loaders.doctree new file mode 100644 index 000000000..f6b81016f Binary files /dev/null and b/.doctrees/api/iblrig.raw_data_loaders.doctree differ diff --git a/.doctrees/api/iblrig.raw_data_loaders.load_task_jsonable.doctree b/.doctrees/api/iblrig.raw_data_loaders.load_task_jsonable.doctree new file mode 100644 index 000000000..3dc498112 Binary files /dev/null and b/.doctrees/api/iblrig.raw_data_loaders.load_task_jsonable.doctree differ diff --git a/.doctrees/api/iblrig.rig_component.RigComponent.doctree b/.doctrees/api/iblrig.rig_component.RigComponent.doctree new file mode 100644 index 000000000..36db0e62d Binary files /dev/null and b/.doctrees/api/iblrig.rig_component.RigComponent.doctree differ diff --git a/.doctrees/api/iblrig.rig_component.doctree b/.doctrees/api/iblrig.rig_component.doctree new file mode 100644 index 000000000..e5616b0aa Binary files /dev/null and b/.doctrees/api/iblrig.rig_component.doctree differ diff --git a/.doctrees/api/iblrig.scale.Scale.doctree b/.doctrees/api/iblrig.scale.Scale.doctree new file mode 100644 index 000000000..160f066a4 Binary files /dev/null and b/.doctrees/api/iblrig.scale.Scale.doctree differ diff --git a/.doctrees/api/iblrig.scale.ScaleData.doctree b/.doctrees/api/iblrig.scale.ScaleData.doctree new file mode 100644 index 000000000..3d79e56ff Binary files /dev/null and b/.doctrees/api/iblrig.scale.ScaleData.doctree differ diff --git a/.doctrees/api/iblrig.scale.doctree b/.doctrees/api/iblrig.scale.doctree new file mode 100644 index 000000000..fb52c5c14 Binary files /dev/null and b/.doctrees/api/iblrig.scale.doctree differ diff --git a/.doctrees/api/iblrig.serial_singleton.SerialSingleton.doctree b/.doctrees/api/iblrig.serial_singleton.SerialSingleton.doctree new file mode 100644 index 000000000..bcaefae50 Binary files /dev/null and b/.doctrees/api/iblrig.serial_singleton.SerialSingleton.doctree differ diff --git a/.doctrees/api/iblrig.serial_singleton.SerialSingletonException.doctree b/.doctrees/api/iblrig.serial_singleton.SerialSingletonException.doctree new file mode 100644 index 000000000..86478202c Binary files /dev/null and b/.doctrees/api/iblrig.serial_singleton.SerialSingletonException.doctree differ diff --git a/.doctrees/api/iblrig.serial_singleton.doctree b/.doctrees/api/iblrig.serial_singleton.doctree new file mode 100644 index 000000000..cc56ad93c Binary files /dev/null and b/.doctrees/api/iblrig.serial_singleton.doctree differ diff --git a/.doctrees/api/iblrig.serial_singleton.filter_ports.doctree b/.doctrees/api/iblrig.serial_singleton.filter_ports.doctree new file mode 100644 index 000000000..535701ca5 Binary files /dev/null and b/.doctrees/api/iblrig.serial_singleton.filter_ports.doctree differ diff --git a/.doctrees/api/iblrig.serial_singleton.get_port_from_serial_number.doctree b/.doctrees/api/iblrig.serial_singleton.get_port_from_serial_number.doctree new file mode 100644 index 000000000..2a8fabd8b Binary files /dev/null and b/.doctrees/api/iblrig.serial_singleton.get_port_from_serial_number.doctree differ diff --git a/.doctrees/api/iblrig.serial_singleton.get_serial_number_from_port.doctree b/.doctrees/api/iblrig.serial_singleton.get_serial_number_from_port.doctree new file mode 100644 index 000000000..07e95636f Binary files /dev/null and b/.doctrees/api/iblrig.serial_singleton.get_serial_number_from_port.doctree differ diff --git a/.doctrees/api/iblrig.session_creator.doctree b/.doctrees/api/iblrig.session_creator.doctree new file mode 100644 index 000000000..92f2eecb3 Binary files /dev/null and b/.doctrees/api/iblrig.session_creator.doctree differ diff --git a/.doctrees/api/iblrig.session_creator.draw_block_len.doctree b/.doctrees/api/iblrig.session_creator.draw_block_len.doctree new file mode 100644 index 000000000..fc96449ef Binary files /dev/null and b/.doctrees/api/iblrig.session_creator.draw_block_len.doctree differ diff --git a/.doctrees/api/iblrig.session_creator.draw_position.doctree b/.doctrees/api/iblrig.session_creator.draw_position.doctree new file mode 100644 index 000000000..6c35227a0 Binary files /dev/null and b/.doctrees/api/iblrig.session_creator.draw_position.doctree differ diff --git a/.doctrees/api/iblrig.session_creator.make_ephyscw_pc.doctree b/.doctrees/api/iblrig.session_creator.make_ephyscw_pc.doctree new file mode 100644 index 000000000..71f8eb053 Binary files /dev/null and b/.doctrees/api/iblrig.session_creator.make_ephyscw_pc.doctree differ diff --git a/.doctrees/api/iblrig.sound.configure_sound_card.doctree b/.doctrees/api/iblrig.sound.configure_sound_card.doctree new file mode 100644 index 000000000..711034054 Binary files /dev/null and b/.doctrees/api/iblrig.sound.configure_sound_card.doctree differ diff --git a/.doctrees/api/iblrig.sound.doctree b/.doctrees/api/iblrig.sound.doctree new file mode 100644 index 000000000..d0b61ccc5 Binary files /dev/null and b/.doctrees/api/iblrig.sound.doctree differ diff --git a/.doctrees/api/iblrig.sound.format_sound.doctree b/.doctrees/api/iblrig.sound.format_sound.doctree new file mode 100644 index 000000000..8fb00cfef Binary files /dev/null and b/.doctrees/api/iblrig.sound.format_sound.doctree differ diff --git a/.doctrees/api/iblrig.sound.make_sound.doctree b/.doctrees/api/iblrig.sound.make_sound.doctree new file mode 100644 index 000000000..4c8c597fd Binary files /dev/null and b/.doctrees/api/iblrig.sound.make_sound.doctree differ diff --git a/.doctrees/api/iblrig.tools.ANSI.doctree b/.doctrees/api/iblrig.tools.ANSI.doctree new file mode 100644 index 000000000..6cfbeb39f Binary files /dev/null and b/.doctrees/api/iblrig.tools.ANSI.doctree differ diff --git a/.doctrees/api/iblrig.tools.alyx_reachable.doctree b/.doctrees/api/iblrig.tools.alyx_reachable.doctree new file mode 100644 index 000000000..0369da75d Binary files /dev/null and b/.doctrees/api/iblrig.tools.alyx_reachable.doctree differ diff --git a/.doctrees/api/iblrig.tools.ask_user.doctree b/.doctrees/api/iblrig.tools.ask_user.doctree new file mode 100644 index 000000000..e1cf5b322 Binary files /dev/null and b/.doctrees/api/iblrig.tools.ask_user.doctree differ diff --git a/.doctrees/api/iblrig.tools.call_bonsai.doctree b/.doctrees/api/iblrig.tools.call_bonsai.doctree new file mode 100644 index 000000000..7396351ad Binary files /dev/null and b/.doctrees/api/iblrig.tools.call_bonsai.doctree differ diff --git a/.doctrees/api/iblrig.tools.call_bonsai_async.doctree b/.doctrees/api/iblrig.tools.call_bonsai_async.doctree new file mode 100644 index 000000000..92a4c7ed1 Binary files /dev/null and b/.doctrees/api/iblrig.tools.call_bonsai_async.doctree differ diff --git a/.doctrees/api/iblrig.tools.doctree b/.doctrees/api/iblrig.tools.doctree new file mode 100644 index 000000000..73ffba8d3 Binary files /dev/null and b/.doctrees/api/iblrig.tools.doctree differ diff --git a/.doctrees/api/iblrig.tools.get_anydesk_id.doctree b/.doctrees/api/iblrig.tools.get_anydesk_id.doctree new file mode 100644 index 000000000..3e13d6c29 Binary files /dev/null and b/.doctrees/api/iblrig.tools.get_anydesk_id.doctree differ diff --git a/.doctrees/api/iblrig.tools.get_inheritors.doctree b/.doctrees/api/iblrig.tools.get_inheritors.doctree new file mode 100644 index 000000000..64363b847 Binary files /dev/null and b/.doctrees/api/iblrig.tools.get_inheritors.doctree differ diff --git a/.doctrees/api/iblrig.tools.get_lab_location_dict.doctree b/.doctrees/api/iblrig.tools.get_lab_location_dict.doctree new file mode 100644 index 000000000..797289a6a Binary files /dev/null and b/.doctrees/api/iblrig.tools.get_lab_location_dict.doctree differ diff --git a/.doctrees/api/iblrig.tools.internet_available.doctree b/.doctrees/api/iblrig.tools.internet_available.doctree new file mode 100644 index 000000000..3e8a77d74 Binary files /dev/null and b/.doctrees/api/iblrig.tools.internet_available.doctree differ diff --git a/.doctrees/api/iblrig.tools.static_vars.doctree b/.doctrees/api/iblrig.tools.static_vars.doctree new file mode 100644 index 000000000..e9268c0ca Binary files /dev/null and b/.doctrees/api/iblrig.tools.static_vars.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.BehaviorCopier.doctree b/.doctrees/api/iblrig.transfer_experiments.BehaviorCopier.doctree new file mode 100644 index 000000000..9fd8e4ea4 Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.BehaviorCopier.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.CopyState.doctree b/.doctrees/api/iblrig.transfer_experiments.CopyState.doctree new file mode 100644 index 000000000..932a06ad3 Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.CopyState.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.EphysCopier.doctree b/.doctrees/api/iblrig.transfer_experiments.EphysCopier.doctree new file mode 100644 index 000000000..c181124c4 Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.EphysCopier.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.SessionCopier.doctree b/.doctrees/api/iblrig.transfer_experiments.SessionCopier.doctree new file mode 100644 index 000000000..a11c1a14e Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.SessionCopier.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.VideoCopier.doctree b/.doctrees/api/iblrig.transfer_experiments.VideoCopier.doctree new file mode 100644 index 000000000..268acecf2 Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.VideoCopier.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.copy_folders.doctree b/.doctrees/api/iblrig.transfer_experiments.copy_folders.doctree new file mode 100644 index 000000000..dcd266d85 Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.copy_folders.doctree differ diff --git a/.doctrees/api/iblrig.transfer_experiments.doctree b/.doctrees/api/iblrig.transfer_experiments.doctree new file mode 100644 index 000000000..379135193 Binary files /dev/null and b/.doctrees/api/iblrig.transfer_experiments.doctree differ diff --git a/.doctrees/api/iblrig.upgrade_iblrig.call_subprocesses.doctree b/.doctrees/api/iblrig.upgrade_iblrig.call_subprocesses.doctree new file mode 100644 index 000000000..5ad143a18 Binary files /dev/null and b/.doctrees/api/iblrig.upgrade_iblrig.call_subprocesses.doctree differ diff --git a/.doctrees/api/iblrig.upgrade_iblrig.doctree b/.doctrees/api/iblrig.upgrade_iblrig.doctree new file mode 100644 index 000000000..b7da6b335 Binary files /dev/null and b/.doctrees/api/iblrig.upgrade_iblrig.doctree differ diff --git a/.doctrees/api/iblrig.upgrade_iblrig.upgrade.doctree b/.doctrees/api/iblrig.upgrade_iblrig.upgrade.doctree new file mode 100644 index 000000000..f2770062c Binary files /dev/null and b/.doctrees/api/iblrig.upgrade_iblrig.upgrade.doctree differ diff --git a/.doctrees/api/iblrig.valve.Valve.doctree b/.doctrees/api/iblrig.valve.Valve.doctree new file mode 100644 index 000000000..59ccf7f1b Binary files /dev/null and b/.doctrees/api/iblrig.valve.Valve.doctree differ diff --git a/.doctrees/api/iblrig.valve.ValveValues.doctree b/.doctrees/api/iblrig.valve.ValveValues.doctree new file mode 100644 index 000000000..84f7c1c5b Binary files /dev/null and b/.doctrees/api/iblrig.valve.ValveValues.doctree differ diff --git a/.doctrees/api/iblrig.valve.doctree b/.doctrees/api/iblrig.valve.doctree new file mode 100644 index 000000000..e6451e0c5 Binary files /dev/null and b/.doctrees/api/iblrig.valve.doctree differ diff --git a/.doctrees/api/iblrig.version_management.call_git.doctree b/.doctrees/api/iblrig.version_management.call_git.doctree new file mode 100644 index 000000000..7e0bef955 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.call_git.doctree differ diff --git a/.doctrees/api/iblrig.version_management.check_for_updates.doctree b/.doctrees/api/iblrig.version_management.check_for_updates.doctree new file mode 100644 index 000000000..65c061310 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.check_for_updates.doctree differ diff --git a/.doctrees/api/iblrig.version_management.check_upgrade_prerequisites.doctree b/.doctrees/api/iblrig.version_management.check_upgrade_prerequisites.doctree new file mode 100644 index 000000000..e79fa587e Binary files /dev/null and b/.doctrees/api/iblrig.version_management.check_upgrade_prerequisites.doctree differ diff --git a/.doctrees/api/iblrig.version_management.doctree b/.doctrees/api/iblrig.version_management.doctree new file mode 100644 index 000000000..54967f427 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_branch.doctree b/.doctrees/api/iblrig.version_management.get_branch.doctree new file mode 100644 index 000000000..5554d0545 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_branch.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_changelog.doctree b/.doctrees/api/iblrig.version_management.get_changelog.doctree new file mode 100644 index 000000000..71c16a36d Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_changelog.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_commit_hash.doctree b/.doctrees/api/iblrig.version_management.get_commit_hash.doctree new file mode 100644 index 000000000..b71bf0085 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_commit_hash.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_detailed_version_string.doctree b/.doctrees/api/iblrig.version_management.get_detailed_version_string.doctree new file mode 100644 index 000000000..391c05dfa Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_detailed_version_string.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_local_version.doctree b/.doctrees/api/iblrig.version_management.get_local_version.doctree new file mode 100644 index 000000000..1becc0261 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_local_version.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_remote_tags.doctree b/.doctrees/api/iblrig.version_management.get_remote_tags.doctree new file mode 100644 index 000000000..d8d3cbf65 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_remote_tags.doctree differ diff --git a/.doctrees/api/iblrig.version_management.get_remote_version.doctree b/.doctrees/api/iblrig.version_management.get_remote_version.doctree new file mode 100644 index 000000000..a38ca1b40 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.get_remote_version.doctree differ diff --git a/.doctrees/api/iblrig.version_management.is_dirty.doctree b/.doctrees/api/iblrig.version_management.is_dirty.doctree new file mode 100644 index 000000000..e457a24f0 Binary files /dev/null and b/.doctrees/api/iblrig.version_management.is_dirty.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.doctree new file mode 100644 index 000000000..230d6eca5 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..ccd67a3a4 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.doctree new file mode 100644 index 000000000..329ceee1b Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.doctree new file mode 100644 index 000000000..a9066fc12 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..b12150066 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.doctree new file mode 100644 index 000000000..d10ff421e Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.doctree new file mode 100644 index 000000000..198d47b6c Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..9b5f7f90a Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.doctree new file mode 100644 index 000000000..44dc05f11 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.doctree new file mode 100644 index 000000000..bddb6fad0 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..b620d1bd8 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.doctree new file mode 100644 index 000000000..85ff2fb8b Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.doctree new file mode 100644 index 000000000..eb9b3845f Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..55203333b Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.doctree new file mode 100644 index 000000000..0f6dea334 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.doctree new file mode 100644 index 000000000..fd8c23fdd Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.doctree new file mode 100644 index 000000000..49504fbed Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..3d96cd70c Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.doctree new file mode 100644 index 000000000..53acb3e59 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.doctree new file mode 100644 index 000000000..1b7ddfd1f Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.doctree new file mode 100644 index 000000000..bb52333ed Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..825ecdf48 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.doctree new file mode 100644 index 000000000..3d0c3fda7 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.doctree new file mode 100644 index 000000000..7b91c0909 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.doctree new file mode 100644 index 000000000..68ad732ff Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.task.doctree new file mode 100644 index 000000000..8815e03c4 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_spontaneous.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.doctree new file mode 100644 index 000000000..14fe4685e Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..718fc8549 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.doctree new file mode 100644 index 000000000..dcea1db57 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.doctree new file mode 100644 index 000000000..a0cc09ce3 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.doctree new file mode 100644 index 000000000..4de8a97cb Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.doctree new file mode 100644 index 000000000..2ac971161 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.doctree differ diff --git a/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.doctree b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.doctree new file mode 100644 index 000000000..8c48f0900 Binary files /dev/null and b/.doctrees/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.doctree differ diff --git a/.doctrees/api/iblrig_tasks.doctree b/.doctrees/api/iblrig_tasks.doctree new file mode 100644 index 000000000..22b0ea167 Binary files /dev/null and b/.doctrees/api/iblrig_tasks.doctree differ diff --git a/.doctrees/changelog.doctree b/.doctrees/changelog.doctree new file mode 100644 index 000000000..5a928e886 Binary files /dev/null and b/.doctrees/changelog.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle new file mode 100644 index 000000000..700caa4d6 Binary files /dev/null and b/.doctrees/environment.pickle differ diff --git a/.doctrees/faq.doctree b/.doctrees/faq.doctree new file mode 100644 index 000000000..ece2d4a99 Binary files /dev/null and b/.doctrees/faq.doctree differ diff --git a/.doctrees/hardware.doctree b/.doctrees/hardware.doctree new file mode 100644 index 000000000..4a57a571b Binary files /dev/null and b/.doctrees/hardware.doctree differ diff --git a/.doctrees/index.doctree b/.doctrees/index.doctree new file mode 100644 index 000000000..06872e75b Binary files /dev/null and b/.doctrees/index.doctree differ diff --git a/.doctrees/installation.doctree b/.doctrees/installation.doctree new file mode 100644 index 000000000..40835efed Binary files /dev/null and b/.doctrees/installation.doctree differ diff --git a/.doctrees/reference.doctree b/.doctrees/reference.doctree new file mode 100644 index 000000000..c2ea58385 Binary files /dev/null and b/.doctrees/reference.doctree differ diff --git a/.doctrees/reference_description_file.doctree b/.doctrees/reference_description_file.doctree new file mode 100644 index 000000000..b18d1851c Binary files /dev/null and b/.doctrees/reference_description_file.doctree differ diff --git a/.doctrees/reference_developer_guide.doctree b/.doctrees/reference_developer_guide.doctree new file mode 100644 index 000000000..cb25b707c Binary files /dev/null and b/.doctrees/reference_developer_guide.doctree differ diff --git a/.doctrees/reference_task_qc.doctree b/.doctrees/reference_task_qc.doctree new file mode 100644 index 000000000..b9878776f Binary files /dev/null and b/.doctrees/reference_task_qc.doctree differ diff --git a/.doctrees/reference_write_your_own_task.doctree b/.doctrees/reference_write_your_own_task.doctree new file mode 100644 index 000000000..f8abc0e25 Binary files /dev/null and b/.doctrees/reference_write_your_own_task.doctree differ diff --git a/.doctrees/usage.doctree b/.doctrees/usage.doctree new file mode 100644 index 000000000..476246eaf Binary files /dev/null and b/.doctrees/usage.doctree differ diff --git a/.doctrees/usage_behavior.doctree b/.doctrees/usage_behavior.doctree new file mode 100644 index 000000000..ee9ca214c Binary files /dev/null and b/.doctrees/usage_behavior.doctree differ diff --git a/.doctrees/usage_copy.doctree b/.doctrees/usage_copy.doctree new file mode 100644 index 000000000..745cfd033 Binary files /dev/null and b/.doctrees/usage_copy.doctree differ diff --git a/.doctrees/usage_neuropixel.doctree b/.doctrees/usage_neuropixel.doctree new file mode 100644 index 000000000..63c87ed5c Binary files /dev/null and b/.doctrees/usage_neuropixel.doctree differ diff --git a/.doctrees/usage_video.doctree b/.doctrees/usage_video.doctree new file mode 100644 index 000000000..afeb63c25 Binary files /dev/null and b/.doctrees/usage_video.doctree differ diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/_images/amp2x15_labels.png b/_images/amp2x15_labels.png new file mode 100644 index 000000000..141638b49 Binary files /dev/null and b/_images/amp2x15_labels.png differ diff --git a/_images/gui.png b/_images/gui.png new file mode 100644 index 000000000..cf0ba1227 Binary files /dev/null and b/_images/gui.png differ diff --git a/_images/hifi_labels.png b/_images/hifi_labels.png new file mode 100644 index 000000000..436428830 Binary files /dev/null and b/_images/hifi_labels.png differ diff --git a/_images/inheritance-00d4e22b8702143f37203f9bc0d32645b7482bb3.png b/_images/inheritance-00d4e22b8702143f37203f9bc0d32645b7482bb3.png new file mode 100644 index 000000000..d4397e920 Binary files /dev/null and b/_images/inheritance-00d4e22b8702143f37203f9bc0d32645b7482bb3.png differ diff --git a/_images/inheritance-00d4e22b8702143f37203f9bc0d32645b7482bb3.png.map b/_images/inheritance-00d4e22b8702143f37203f9bc0d32645b7482bb3.png.map new file mode 100644 index 000000000..c067ece21 --- /dev/null +++ b/_images/inheritance-00d4e22b8702143f37203f9bc0d32645b7482bb3.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-01e5cf62bece4a9d43867a141b4152378f6bbac8.png b/_images/inheritance-01e5cf62bece4a9d43867a141b4152378f6bbac8.png new file mode 100644 index 000000000..ddb53ec45 Binary files /dev/null and b/_images/inheritance-01e5cf62bece4a9d43867a141b4152378f6bbac8.png differ diff --git a/_images/inheritance-01e5cf62bece4a9d43867a141b4152378f6bbac8.png.map b/_images/inheritance-01e5cf62bece4a9d43867a141b4152378f6bbac8.png.map new file mode 100644 index 000000000..ea94cc96b --- /dev/null +++ b/_images/inheritance-01e5cf62bece4a9d43867a141b4152378f6bbac8.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-05a72a67dab81d508ba6a14f62604907a02a4dec.png b/_images/inheritance-05a72a67dab81d508ba6a14f62604907a02a4dec.png new file mode 100644 index 000000000..9298789d1 Binary files /dev/null and b/_images/inheritance-05a72a67dab81d508ba6a14f62604907a02a4dec.png differ diff --git a/_images/inheritance-05a72a67dab81d508ba6a14f62604907a02a4dec.png.map b/_images/inheritance-05a72a67dab81d508ba6a14f62604907a02a4dec.png.map new file mode 100644 index 000000000..9cfecc6c7 --- /dev/null +++ b/_images/inheritance-05a72a67dab81d508ba6a14f62604907a02a4dec.png.map @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/_images/inheritance-05dce2d109e90b0ec9c8f4818c0078ae494485d7.png b/_images/inheritance-05dce2d109e90b0ec9c8f4818c0078ae494485d7.png new file mode 100644 index 000000000..5c0b9a0f8 Binary files /dev/null and b/_images/inheritance-05dce2d109e90b0ec9c8f4818c0078ae494485d7.png differ diff --git a/_images/inheritance-05dce2d109e90b0ec9c8f4818c0078ae494485d7.png.map b/_images/inheritance-05dce2d109e90b0ec9c8f4818c0078ae494485d7.png.map new file mode 100644 index 000000000..aaf6b97e9 --- /dev/null +++ b/_images/inheritance-05dce2d109e90b0ec9c8f4818c0078ae494485d7.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-089821f958eed42ed185fde6164951791a68efb2.png b/_images/inheritance-089821f958eed42ed185fde6164951791a68efb2.png new file mode 100644 index 000000000..25fad6ea5 Binary files /dev/null and b/_images/inheritance-089821f958eed42ed185fde6164951791a68efb2.png differ diff --git a/_images/inheritance-089821f958eed42ed185fde6164951791a68efb2.png.map b/_images/inheritance-089821f958eed42ed185fde6164951791a68efb2.png.map new file mode 100644 index 000000000..56de83558 --- /dev/null +++ b/_images/inheritance-089821f958eed42ed185fde6164951791a68efb2.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-097f586b0c791359bbab34867b4afac2f2d264e6.png b/_images/inheritance-097f586b0c791359bbab34867b4afac2f2d264e6.png new file mode 100644 index 000000000..8811b18c8 Binary files /dev/null and b/_images/inheritance-097f586b0c791359bbab34867b4afac2f2d264e6.png differ diff --git a/_images/inheritance-097f586b0c791359bbab34867b4afac2f2d264e6.png.map b/_images/inheritance-097f586b0c791359bbab34867b4afac2f2d264e6.png.map new file mode 100644 index 000000000..4093b465b --- /dev/null +++ b/_images/inheritance-097f586b0c791359bbab34867b4afac2f2d264e6.png.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-0c14956a68db2d52a2a3627deee027de912d3360.png b/_images/inheritance-0c14956a68db2d52a2a3627deee027de912d3360.png new file mode 100644 index 000000000..9de47d0de Binary files /dev/null and b/_images/inheritance-0c14956a68db2d52a2a3627deee027de912d3360.png differ diff --git a/_images/inheritance-0c14956a68db2d52a2a3627deee027de912d3360.png.map b/_images/inheritance-0c14956a68db2d52a2a3627deee027de912d3360.png.map new file mode 100644 index 000000000..4a1b933b5 --- /dev/null +++ b/_images/inheritance-0c14956a68db2d52a2a3627deee027de912d3360.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-0d186f841a39716398fe2704724d17070edd776d.png b/_images/inheritance-0d186f841a39716398fe2704724d17070edd776d.png new file mode 100644 index 000000000..8811b18c8 Binary files /dev/null and b/_images/inheritance-0d186f841a39716398fe2704724d17070edd776d.png differ diff --git a/_images/inheritance-0d186f841a39716398fe2704724d17070edd776d.png.map b/_images/inheritance-0d186f841a39716398fe2704724d17070edd776d.png.map new file mode 100644 index 000000000..65fc67084 --- /dev/null +++ b/_images/inheritance-0d186f841a39716398fe2704724d17070edd776d.png.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-0d6d3b82e3e6faba09f4c4e7ac4f368b60b11b6b.png b/_images/inheritance-0d6d3b82e3e6faba09f4c4e7ac4f368b60b11b6b.png new file mode 100644 index 000000000..df705c4f0 Binary files /dev/null and b/_images/inheritance-0d6d3b82e3e6faba09f4c4e7ac4f368b60b11b6b.png differ diff --git a/_images/inheritance-0d6d3b82e3e6faba09f4c4e7ac4f368b60b11b6b.png.map b/_images/inheritance-0d6d3b82e3e6faba09f4c4e7ac4f368b60b11b6b.png.map new file mode 100644 index 000000000..41b490e10 --- /dev/null +++ b/_images/inheritance-0d6d3b82e3e6faba09f4c4e7ac4f368b60b11b6b.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-1420b9d6cc60c40b6f4a1ae3ef15ef82ba1c68c5.png b/_images/inheritance-1420b9d6cc60c40b6f4a1ae3ef15ef82ba1c68c5.png new file mode 100644 index 000000000..8a61dbd84 Binary files /dev/null and b/_images/inheritance-1420b9d6cc60c40b6f4a1ae3ef15ef82ba1c68c5.png differ diff --git a/_images/inheritance-1420b9d6cc60c40b6f4a1ae3ef15ef82ba1c68c5.png.map b/_images/inheritance-1420b9d6cc60c40b6f4a1ae3ef15ef82ba1c68c5.png.map new file mode 100644 index 000000000..d186ee57c --- /dev/null +++ b/_images/inheritance-1420b9d6cc60c40b6f4a1ae3ef15ef82ba1c68c5.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-16e88b56fe4e8229ede8440ac20a67ea73430770.png b/_images/inheritance-16e88b56fe4e8229ede8440ac20a67ea73430770.png new file mode 100644 index 000000000..72b0520a7 Binary files /dev/null and b/_images/inheritance-16e88b56fe4e8229ede8440ac20a67ea73430770.png differ diff --git a/_images/inheritance-16e88b56fe4e8229ede8440ac20a67ea73430770.png.map b/_images/inheritance-16e88b56fe4e8229ede8440ac20a67ea73430770.png.map new file mode 100644 index 000000000..66ee9fcdb --- /dev/null +++ b/_images/inheritance-16e88b56fe4e8229ede8440ac20a67ea73430770.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-1a3008fb1cdcca33f100f4bfe4ed3bd041f253b3.png b/_images/inheritance-1a3008fb1cdcca33f100f4bfe4ed3bd041f253b3.png new file mode 100644 index 000000000..82f05da60 Binary files /dev/null and b/_images/inheritance-1a3008fb1cdcca33f100f4bfe4ed3bd041f253b3.png differ diff --git a/_images/inheritance-1a3008fb1cdcca33f100f4bfe4ed3bd041f253b3.png.map b/_images/inheritance-1a3008fb1cdcca33f100f4bfe4ed3bd041f253b3.png.map new file mode 100644 index 000000000..cc0ed1a27 --- /dev/null +++ b/_images/inheritance-1a3008fb1cdcca33f100f4bfe4ed3bd041f253b3.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-1add4e80ee4a8171fb0331230a8f4bce8d1d6a30.png b/_images/inheritance-1add4e80ee4a8171fb0331230a8f4bce8d1d6a30.png new file mode 100644 index 000000000..1824ce819 Binary files /dev/null and b/_images/inheritance-1add4e80ee4a8171fb0331230a8f4bce8d1d6a30.png differ diff --git a/_images/inheritance-1add4e80ee4a8171fb0331230a8f4bce8d1d6a30.png.map b/_images/inheritance-1add4e80ee4a8171fb0331230a8f4bce8d1d6a30.png.map new file mode 100644 index 000000000..1d657c277 --- /dev/null +++ b/_images/inheritance-1add4e80ee4a8171fb0331230a8f4bce8d1d6a30.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-1d215958ac6eda261e155ab7bc08db18cb0cf5a0.png b/_images/inheritance-1d215958ac6eda261e155ab7bc08db18cb0cf5a0.png new file mode 100644 index 000000000..56e880918 Binary files /dev/null and b/_images/inheritance-1d215958ac6eda261e155ab7bc08db18cb0cf5a0.png differ diff --git a/_images/inheritance-1d215958ac6eda261e155ab7bc08db18cb0cf5a0.png.map b/_images/inheritance-1d215958ac6eda261e155ab7bc08db18cb0cf5a0.png.map new file mode 100644 index 000000000..04a7ed352 --- /dev/null +++ b/_images/inheritance-1d215958ac6eda261e155ab7bc08db18cb0cf5a0.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-1d4436ab1d791b5fcf62d032d148c62e73d94de8.png b/_images/inheritance-1d4436ab1d791b5fcf62d032d148c62e73d94de8.png new file mode 100644 index 000000000..4904c02ce Binary files /dev/null and b/_images/inheritance-1d4436ab1d791b5fcf62d032d148c62e73d94de8.png differ diff --git a/_images/inheritance-1d4436ab1d791b5fcf62d032d148c62e73d94de8.png.map b/_images/inheritance-1d4436ab1d791b5fcf62d032d148c62e73d94de8.png.map new file mode 100644 index 000000000..35f179cc7 --- /dev/null +++ b/_images/inheritance-1d4436ab1d791b5fcf62d032d148c62e73d94de8.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-1d512d363827a66e97742773a527f88af4fba97e.png b/_images/inheritance-1d512d363827a66e97742773a527f88af4fba97e.png new file mode 100644 index 000000000..3eb285c1f Binary files /dev/null and b/_images/inheritance-1d512d363827a66e97742773a527f88af4fba97e.png differ diff --git a/_images/inheritance-1d512d363827a66e97742773a527f88af4fba97e.png.map b/_images/inheritance-1d512d363827a66e97742773a527f88af4fba97e.png.map new file mode 100644 index 000000000..dad3082d4 --- /dev/null +++ b/_images/inheritance-1d512d363827a66e97742773a527f88af4fba97e.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-1d5995b710cc5588d837e10a7c16acd38b101734.png b/_images/inheritance-1d5995b710cc5588d837e10a7c16acd38b101734.png new file mode 100644 index 000000000..90fa061ac Binary files /dev/null and b/_images/inheritance-1d5995b710cc5588d837e10a7c16acd38b101734.png differ diff --git a/_images/inheritance-1d5995b710cc5588d837e10a7c16acd38b101734.png.map b/_images/inheritance-1d5995b710cc5588d837e10a7c16acd38b101734.png.map new file mode 100644 index 000000000..a70ff22e8 --- /dev/null +++ b/_images/inheritance-1d5995b710cc5588d837e10a7c16acd38b101734.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-21c189dcca65dac77dc490c26bdaad9455fc81c4.png b/_images/inheritance-21c189dcca65dac77dc490c26bdaad9455fc81c4.png new file mode 100644 index 000000000..641733315 Binary files /dev/null and b/_images/inheritance-21c189dcca65dac77dc490c26bdaad9455fc81c4.png differ diff --git a/_images/inheritance-21c189dcca65dac77dc490c26bdaad9455fc81c4.png.map b/_images/inheritance-21c189dcca65dac77dc490c26bdaad9455fc81c4.png.map new file mode 100644 index 000000000..99bd1cfed --- /dev/null +++ b/_images/inheritance-21c189dcca65dac77dc490c26bdaad9455fc81c4.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-22e207cc387349eea193c7d59825bb408de52aff.png b/_images/inheritance-22e207cc387349eea193c7d59825bb408de52aff.png new file mode 100644 index 000000000..e9bf0a328 Binary files /dev/null and b/_images/inheritance-22e207cc387349eea193c7d59825bb408de52aff.png differ diff --git a/_images/inheritance-22e207cc387349eea193c7d59825bb408de52aff.png.map b/_images/inheritance-22e207cc387349eea193c7d59825bb408de52aff.png.map new file mode 100644 index 000000000..159c6b1f1 --- /dev/null +++ b/_images/inheritance-22e207cc387349eea193c7d59825bb408de52aff.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-2436f87f2dfaf91faaf8ee9f72ce5eb6df3c59fd.png b/_images/inheritance-2436f87f2dfaf91faaf8ee9f72ce5eb6df3c59fd.png new file mode 100644 index 000000000..0f745b16d Binary files /dev/null and b/_images/inheritance-2436f87f2dfaf91faaf8ee9f72ce5eb6df3c59fd.png differ diff --git a/_images/inheritance-2436f87f2dfaf91faaf8ee9f72ce5eb6df3c59fd.png.map b/_images/inheritance-2436f87f2dfaf91faaf8ee9f72ce5eb6df3c59fd.png.map new file mode 100644 index 000000000..cb4923caf --- /dev/null +++ b/_images/inheritance-2436f87f2dfaf91faaf8ee9f72ce5eb6df3c59fd.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-264b184fe07c8a9457fe41991537378e2f5a9bf6.png b/_images/inheritance-264b184fe07c8a9457fe41991537378e2f5a9bf6.png new file mode 100644 index 000000000..2fd7d0341 Binary files /dev/null and b/_images/inheritance-264b184fe07c8a9457fe41991537378e2f5a9bf6.png differ diff --git a/_images/inheritance-264b184fe07c8a9457fe41991537378e2f5a9bf6.png.map b/_images/inheritance-264b184fe07c8a9457fe41991537378e2f5a9bf6.png.map new file mode 100644 index 000000000..3580e3918 --- /dev/null +++ b/_images/inheritance-264b184fe07c8a9457fe41991537378e2f5a9bf6.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-2702369b9b65cbee767eec6d565f406bb6ba273a.png b/_images/inheritance-2702369b9b65cbee767eec6d565f406bb6ba273a.png new file mode 100644 index 000000000..defa4fc47 Binary files /dev/null and b/_images/inheritance-2702369b9b65cbee767eec6d565f406bb6ba273a.png differ diff --git a/_images/inheritance-2702369b9b65cbee767eec6d565f406bb6ba273a.png.map b/_images/inheritance-2702369b9b65cbee767eec6d565f406bb6ba273a.png.map new file mode 100644 index 000000000..24fe1db0d --- /dev/null +++ b/_images/inheritance-2702369b9b65cbee767eec6d565f406bb6ba273a.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-2a2bc5ba6237a818420873ff4ae709188f0e3a39.png b/_images/inheritance-2a2bc5ba6237a818420873ff4ae709188f0e3a39.png new file mode 100644 index 000000000..1b7f8bac7 Binary files /dev/null and b/_images/inheritance-2a2bc5ba6237a818420873ff4ae709188f0e3a39.png differ diff --git a/_images/inheritance-2a2bc5ba6237a818420873ff4ae709188f0e3a39.png.map b/_images/inheritance-2a2bc5ba6237a818420873ff4ae709188f0e3a39.png.map new file mode 100644 index 000000000..175e2eb52 --- /dev/null +++ b/_images/inheritance-2a2bc5ba6237a818420873ff4ae709188f0e3a39.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-2b77faabda364e5ba4aa3ea3a79903e4d5ec5434.png b/_images/inheritance-2b77faabda364e5ba4aa3ea3a79903e4d5ec5434.png new file mode 100644 index 000000000..e1dc3c7bc Binary files /dev/null and b/_images/inheritance-2b77faabda364e5ba4aa3ea3a79903e4d5ec5434.png differ diff --git a/_images/inheritance-2b77faabda364e5ba4aa3ea3a79903e4d5ec5434.png.map b/_images/inheritance-2b77faabda364e5ba4aa3ea3a79903e4d5ec5434.png.map new file mode 100644 index 000000000..a6a86bd72 --- /dev/null +++ b/_images/inheritance-2b77faabda364e5ba4aa3ea3a79903e4d5ec5434.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-2e5c825106643a6078d8e03196cc7205ced5c4c0.png b/_images/inheritance-2e5c825106643a6078d8e03196cc7205ced5c4c0.png new file mode 100644 index 000000000..4ce1621a5 Binary files /dev/null and b/_images/inheritance-2e5c825106643a6078d8e03196cc7205ced5c4c0.png differ diff --git a/_images/inheritance-2e5c825106643a6078d8e03196cc7205ced5c4c0.png.map b/_images/inheritance-2e5c825106643a6078d8e03196cc7205ced5c4c0.png.map new file mode 100644 index 000000000..7b10d8f98 --- /dev/null +++ b/_images/inheritance-2e5c825106643a6078d8e03196cc7205ced5c4c0.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-34569d12e07a172ce36bfbd38c451d96faecf3b5.png b/_images/inheritance-34569d12e07a172ce36bfbd38c451d96faecf3b5.png new file mode 100644 index 000000000..451bd47ea Binary files /dev/null and b/_images/inheritance-34569d12e07a172ce36bfbd38c451d96faecf3b5.png differ diff --git a/_images/inheritance-34569d12e07a172ce36bfbd38c451d96faecf3b5.png.map b/_images/inheritance-34569d12e07a172ce36bfbd38c451d96faecf3b5.png.map new file mode 100644 index 000000000..dc603a26a --- /dev/null +++ b/_images/inheritance-34569d12e07a172ce36bfbd38c451d96faecf3b5.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-34ca386b2fb8b8f608f579a0d308b6d8cbc5bedb.png b/_images/inheritance-34ca386b2fb8b8f608f579a0d308b6d8cbc5bedb.png new file mode 100644 index 000000000..8b21cbc95 Binary files /dev/null and b/_images/inheritance-34ca386b2fb8b8f608f579a0d308b6d8cbc5bedb.png differ diff --git a/_images/inheritance-34ca386b2fb8b8f608f579a0d308b6d8cbc5bedb.png.map b/_images/inheritance-34ca386b2fb8b8f608f579a0d308b6d8cbc5bedb.png.map new file mode 100644 index 000000000..c23f5470b --- /dev/null +++ b/_images/inheritance-34ca386b2fb8b8f608f579a0d308b6d8cbc5bedb.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-38c7b91022f979a7eb3fe9863df5f5ec1af2fa4d.png b/_images/inheritance-38c7b91022f979a7eb3fe9863df5f5ec1af2fa4d.png new file mode 100644 index 000000000..0804a4ea9 Binary files /dev/null and b/_images/inheritance-38c7b91022f979a7eb3fe9863df5f5ec1af2fa4d.png differ diff --git a/_images/inheritance-38c7b91022f979a7eb3fe9863df5f5ec1af2fa4d.png.map b/_images/inheritance-38c7b91022f979a7eb3fe9863df5f5ec1af2fa4d.png.map new file mode 100644 index 000000000..8d5a2940c --- /dev/null +++ b/_images/inheritance-38c7b91022f979a7eb3fe9863df5f5ec1af2fa4d.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-3dc280ebfd9ee20d3a85bb43cb3da7ce4f25b5da.png b/_images/inheritance-3dc280ebfd9ee20d3a85bb43cb3da7ce4f25b5da.png new file mode 100644 index 000000000..514d44eb8 Binary files /dev/null and b/_images/inheritance-3dc280ebfd9ee20d3a85bb43cb3da7ce4f25b5da.png differ diff --git a/_images/inheritance-3dc280ebfd9ee20d3a85bb43cb3da7ce4f25b5da.png.map b/_images/inheritance-3dc280ebfd9ee20d3a85bb43cb3da7ce4f25b5da.png.map new file mode 100644 index 000000000..17c7c3b40 --- /dev/null +++ b/_images/inheritance-3dc280ebfd9ee20d3a85bb43cb3da7ce4f25b5da.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-3e4c398801fe9b555e15da00e924b323364788f5.png b/_images/inheritance-3e4c398801fe9b555e15da00e924b323364788f5.png new file mode 100644 index 000000000..5afadde6c Binary files /dev/null and b/_images/inheritance-3e4c398801fe9b555e15da00e924b323364788f5.png differ diff --git a/_images/inheritance-3e4c398801fe9b555e15da00e924b323364788f5.png.map b/_images/inheritance-3e4c398801fe9b555e15da00e924b323364788f5.png.map new file mode 100644 index 000000000..30216e8e8 --- /dev/null +++ b/_images/inheritance-3e4c398801fe9b555e15da00e924b323364788f5.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-46e045abb8a28143dced92935500c0da6a0fdd96.png b/_images/inheritance-46e045abb8a28143dced92935500c0da6a0fdd96.png new file mode 100644 index 000000000..445ac3ddc Binary files /dev/null and b/_images/inheritance-46e045abb8a28143dced92935500c0da6a0fdd96.png differ diff --git a/_images/inheritance-46e045abb8a28143dced92935500c0da6a0fdd96.png.map b/_images/inheritance-46e045abb8a28143dced92935500c0da6a0fdd96.png.map new file mode 100644 index 000000000..31a7fc925 --- /dev/null +++ b/_images/inheritance-46e045abb8a28143dced92935500c0da6a0fdd96.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-49f20a0613ad45b9335ebc9b4f17a3bf5d3fc151.png b/_images/inheritance-49f20a0613ad45b9335ebc9b4f17a3bf5d3fc151.png new file mode 100644 index 000000000..924642681 Binary files /dev/null and b/_images/inheritance-49f20a0613ad45b9335ebc9b4f17a3bf5d3fc151.png differ diff --git a/_images/inheritance-49f20a0613ad45b9335ebc9b4f17a3bf5d3fc151.png.map b/_images/inheritance-49f20a0613ad45b9335ebc9b4f17a3bf5d3fc151.png.map new file mode 100644 index 000000000..5b61629ee --- /dev/null +++ b/_images/inheritance-49f20a0613ad45b9335ebc9b4f17a3bf5d3fc151.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-4af3aeda485a56b185b45acda574c0ff8321a134.png b/_images/inheritance-4af3aeda485a56b185b45acda574c0ff8321a134.png new file mode 100644 index 000000000..397c245da Binary files /dev/null and b/_images/inheritance-4af3aeda485a56b185b45acda574c0ff8321a134.png differ diff --git a/_images/inheritance-4af3aeda485a56b185b45acda574c0ff8321a134.png.map b/_images/inheritance-4af3aeda485a56b185b45acda574c0ff8321a134.png.map new file mode 100644 index 000000000..a42daa75d --- /dev/null +++ b/_images/inheritance-4af3aeda485a56b185b45acda574c0ff8321a134.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-4c867d778a6a84e794d37e04566ea65c448f0d8e.png b/_images/inheritance-4c867d778a6a84e794d37e04566ea65c448f0d8e.png new file mode 100644 index 000000000..782eb2eff Binary files /dev/null and b/_images/inheritance-4c867d778a6a84e794d37e04566ea65c448f0d8e.png differ diff --git a/_images/inheritance-4c867d778a6a84e794d37e04566ea65c448f0d8e.png.map b/_images/inheritance-4c867d778a6a84e794d37e04566ea65c448f0d8e.png.map new file mode 100644 index 000000000..0b230d3b5 --- /dev/null +++ b/_images/inheritance-4c867d778a6a84e794d37e04566ea65c448f0d8e.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-4e61557d8f6ee7735648b90e8774b4272d476121.png b/_images/inheritance-4e61557d8f6ee7735648b90e8774b4272d476121.png new file mode 100644 index 000000000..09e86ae77 Binary files /dev/null and b/_images/inheritance-4e61557d8f6ee7735648b90e8774b4272d476121.png differ diff --git a/_images/inheritance-4e61557d8f6ee7735648b90e8774b4272d476121.png.map b/_images/inheritance-4e61557d8f6ee7735648b90e8774b4272d476121.png.map new file mode 100644 index 000000000..8b6bf98b3 --- /dev/null +++ b/_images/inheritance-4e61557d8f6ee7735648b90e8774b4272d476121.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-4f17a2b0c0154c7dfbc409eaf142904510f1b6b7.png b/_images/inheritance-4f17a2b0c0154c7dfbc409eaf142904510f1b6b7.png new file mode 100644 index 000000000..777471578 Binary files /dev/null and b/_images/inheritance-4f17a2b0c0154c7dfbc409eaf142904510f1b6b7.png differ diff --git a/_images/inheritance-4f17a2b0c0154c7dfbc409eaf142904510f1b6b7.png.map b/_images/inheritance-4f17a2b0c0154c7dfbc409eaf142904510f1b6b7.png.map new file mode 100644 index 000000000..f5d321ada --- /dev/null +++ b/_images/inheritance-4f17a2b0c0154c7dfbc409eaf142904510f1b6b7.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-4f83b5b6cc8f93bd28e1280f456db33d3af88fd3.png b/_images/inheritance-4f83b5b6cc8f93bd28e1280f456db33d3af88fd3.png new file mode 100644 index 000000000..48abe03e3 Binary files /dev/null and b/_images/inheritance-4f83b5b6cc8f93bd28e1280f456db33d3af88fd3.png differ diff --git a/_images/inheritance-4f83b5b6cc8f93bd28e1280f456db33d3af88fd3.png.map b/_images/inheritance-4f83b5b6cc8f93bd28e1280f456db33d3af88fd3.png.map new file mode 100644 index 000000000..273687e78 --- /dev/null +++ b/_images/inheritance-4f83b5b6cc8f93bd28e1280f456db33d3af88fd3.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-4fc4804e4b4d59e45337a9600762fdda0782ca9b.png b/_images/inheritance-4fc4804e4b4d59e45337a9600762fdda0782ca9b.png new file mode 100644 index 000000000..a468603e0 Binary files /dev/null and b/_images/inheritance-4fc4804e4b4d59e45337a9600762fdda0782ca9b.png differ diff --git a/_images/inheritance-4fc4804e4b4d59e45337a9600762fdda0782ca9b.png.map b/_images/inheritance-4fc4804e4b4d59e45337a9600762fdda0782ca9b.png.map new file mode 100644 index 000000000..53c5c55d9 --- /dev/null +++ b/_images/inheritance-4fc4804e4b4d59e45337a9600762fdda0782ca9b.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-503718bac17eca8551842b5e98a2455c4736ee2c.png b/_images/inheritance-503718bac17eca8551842b5e98a2455c4736ee2c.png new file mode 100644 index 000000000..a959a7640 Binary files /dev/null and b/_images/inheritance-503718bac17eca8551842b5e98a2455c4736ee2c.png differ diff --git a/_images/inheritance-503718bac17eca8551842b5e98a2455c4736ee2c.png.map b/_images/inheritance-503718bac17eca8551842b5e98a2455c4736ee2c.png.map new file mode 100644 index 000000000..9241fe5fc --- /dev/null +++ b/_images/inheritance-503718bac17eca8551842b5e98a2455c4736ee2c.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-505225ac0720806358a99652d8a1da31d8b38c3a.png b/_images/inheritance-505225ac0720806358a99652d8a1da31d8b38c3a.png new file mode 100644 index 000000000..01eade796 Binary files /dev/null and b/_images/inheritance-505225ac0720806358a99652d8a1da31d8b38c3a.png differ diff --git a/_images/inheritance-505225ac0720806358a99652d8a1da31d8b38c3a.png.map b/_images/inheritance-505225ac0720806358a99652d8a1da31d8b38c3a.png.map new file mode 100644 index 000000000..6dbd41ca0 --- /dev/null +++ b/_images/inheritance-505225ac0720806358a99652d8a1da31d8b38c3a.png.map @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-5199f52b9e179c8a16bafe7ca479c0a754410711.png b/_images/inheritance-5199f52b9e179c8a16bafe7ca479c0a754410711.png new file mode 100644 index 000000000..ef9e40554 Binary files /dev/null and b/_images/inheritance-5199f52b9e179c8a16bafe7ca479c0a754410711.png differ diff --git a/_images/inheritance-5199f52b9e179c8a16bafe7ca479c0a754410711.png.map b/_images/inheritance-5199f52b9e179c8a16bafe7ca479c0a754410711.png.map new file mode 100644 index 000000000..777b27d2d --- /dev/null +++ b/_images/inheritance-5199f52b9e179c8a16bafe7ca479c0a754410711.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-53815dde809fd5e4146ab22e24f867e315010396.png b/_images/inheritance-53815dde809fd5e4146ab22e24f867e315010396.png new file mode 100644 index 000000000..0e4f72c74 Binary files /dev/null and b/_images/inheritance-53815dde809fd5e4146ab22e24f867e315010396.png differ diff --git a/_images/inheritance-53815dde809fd5e4146ab22e24f867e315010396.png.map b/_images/inheritance-53815dde809fd5e4146ab22e24f867e315010396.png.map new file mode 100644 index 000000000..e0a2a0b69 --- /dev/null +++ b/_images/inheritance-53815dde809fd5e4146ab22e24f867e315010396.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-58bbd16f0b2ec236c31a532ea465983ec27ccefc.png b/_images/inheritance-58bbd16f0b2ec236c31a532ea465983ec27ccefc.png new file mode 100644 index 000000000..315063a0a Binary files /dev/null and b/_images/inheritance-58bbd16f0b2ec236c31a532ea465983ec27ccefc.png differ diff --git a/_images/inheritance-58bbd16f0b2ec236c31a532ea465983ec27ccefc.png.map b/_images/inheritance-58bbd16f0b2ec236c31a532ea465983ec27ccefc.png.map new file mode 100644 index 000000000..add4da4ca --- /dev/null +++ b/_images/inheritance-58bbd16f0b2ec236c31a532ea465983ec27ccefc.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-5931d0b937274209f95552de7faf148f66e43616.png b/_images/inheritance-5931d0b937274209f95552de7faf148f66e43616.png new file mode 100644 index 000000000..883ac6431 Binary files /dev/null and b/_images/inheritance-5931d0b937274209f95552de7faf148f66e43616.png differ diff --git a/_images/inheritance-5931d0b937274209f95552de7faf148f66e43616.png.map b/_images/inheritance-5931d0b937274209f95552de7faf148f66e43616.png.map new file mode 100644 index 000000000..dc338b19b --- /dev/null +++ b/_images/inheritance-5931d0b937274209f95552de7faf148f66e43616.png.map @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-606959b55472382940e5b21aa315b4f9f03134c0.png b/_images/inheritance-606959b55472382940e5b21aa315b4f9f03134c0.png new file mode 100644 index 000000000..9863799f6 Binary files /dev/null and b/_images/inheritance-606959b55472382940e5b21aa315b4f9f03134c0.png differ diff --git a/_images/inheritance-606959b55472382940e5b21aa315b4f9f03134c0.png.map b/_images/inheritance-606959b55472382940e5b21aa315b4f9f03134c0.png.map new file mode 100644 index 000000000..8619e23cf --- /dev/null +++ b/_images/inheritance-606959b55472382940e5b21aa315b4f9f03134c0.png.map @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-6125bf4506611b1b896c6d960a8ac4ffd6e7ab5d.png b/_images/inheritance-6125bf4506611b1b896c6d960a8ac4ffd6e7ab5d.png new file mode 100644 index 000000000..c3b87507f Binary files /dev/null and b/_images/inheritance-6125bf4506611b1b896c6d960a8ac4ffd6e7ab5d.png differ diff --git a/_images/inheritance-6125bf4506611b1b896c6d960a8ac4ffd6e7ab5d.png.map b/_images/inheritance-6125bf4506611b1b896c6d960a8ac4ffd6e7ab5d.png.map new file mode 100644 index 000000000..ce38a074a --- /dev/null +++ b/_images/inheritance-6125bf4506611b1b896c6d960a8ac4ffd6e7ab5d.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-65048e38ed7bc188854eb5d4dde250bf8aa0d5f0.png b/_images/inheritance-65048e38ed7bc188854eb5d4dde250bf8aa0d5f0.png new file mode 100644 index 000000000..5f4be133e Binary files /dev/null and b/_images/inheritance-65048e38ed7bc188854eb5d4dde250bf8aa0d5f0.png differ diff --git a/_images/inheritance-65048e38ed7bc188854eb5d4dde250bf8aa0d5f0.png.map b/_images/inheritance-65048e38ed7bc188854eb5d4dde250bf8aa0d5f0.png.map new file mode 100644 index 000000000..6995adb8e --- /dev/null +++ b/_images/inheritance-65048e38ed7bc188854eb5d4dde250bf8aa0d5f0.png.map @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-67a22332e25113b6c264a1750b8a0a64abb02b34.png b/_images/inheritance-67a22332e25113b6c264a1750b8a0a64abb02b34.png new file mode 100644 index 000000000..7c7d62a1c Binary files /dev/null and b/_images/inheritance-67a22332e25113b6c264a1750b8a0a64abb02b34.png differ diff --git a/_images/inheritance-67a22332e25113b6c264a1750b8a0a64abb02b34.png.map b/_images/inheritance-67a22332e25113b6c264a1750b8a0a64abb02b34.png.map new file mode 100644 index 000000000..bf7d98066 --- /dev/null +++ b/_images/inheritance-67a22332e25113b6c264a1750b8a0a64abb02b34.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-6a76adbd8fe410bd2b6c98a550723c57bdd8f3bd.png b/_images/inheritance-6a76adbd8fe410bd2b6c98a550723c57bdd8f3bd.png new file mode 100644 index 000000000..32eda3043 Binary files /dev/null and b/_images/inheritance-6a76adbd8fe410bd2b6c98a550723c57bdd8f3bd.png differ diff --git a/_images/inheritance-6a76adbd8fe410bd2b6c98a550723c57bdd8f3bd.png.map b/_images/inheritance-6a76adbd8fe410bd2b6c98a550723c57bdd8f3bd.png.map new file mode 100644 index 000000000..9cac03e71 --- /dev/null +++ b/_images/inheritance-6a76adbd8fe410bd2b6c98a550723c57bdd8f3bd.png.map @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-6ae0b56020930b3eb1e4f525c90b05348bb484ac.png b/_images/inheritance-6ae0b56020930b3eb1e4f525c90b05348bb484ac.png new file mode 100644 index 000000000..50a85e84e Binary files /dev/null and b/_images/inheritance-6ae0b56020930b3eb1e4f525c90b05348bb484ac.png differ diff --git a/_images/inheritance-6ae0b56020930b3eb1e4f525c90b05348bb484ac.png.map b/_images/inheritance-6ae0b56020930b3eb1e4f525c90b05348bb484ac.png.map new file mode 100644 index 000000000..7527937a2 --- /dev/null +++ b/_images/inheritance-6ae0b56020930b3eb1e4f525c90b05348bb484ac.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-6c833871f3d09564c9b16ecce6bbcd46bfbadf30.png b/_images/inheritance-6c833871f3d09564c9b16ecce6bbcd46bfbadf30.png new file mode 100644 index 000000000..15c2cf865 Binary files /dev/null and b/_images/inheritance-6c833871f3d09564c9b16ecce6bbcd46bfbadf30.png differ diff --git a/_images/inheritance-6c833871f3d09564c9b16ecce6bbcd46bfbadf30.png.map b/_images/inheritance-6c833871f3d09564c9b16ecce6bbcd46bfbadf30.png.map new file mode 100644 index 000000000..85bfa0a2c --- /dev/null +++ b/_images/inheritance-6c833871f3d09564c9b16ecce6bbcd46bfbadf30.png.map @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-6d04e2f32ae30ecc51861ea4f49f3a7545725ebe.png b/_images/inheritance-6d04e2f32ae30ecc51861ea4f49f3a7545725ebe.png new file mode 100644 index 000000000..959902e74 Binary files /dev/null and b/_images/inheritance-6d04e2f32ae30ecc51861ea4f49f3a7545725ebe.png differ diff --git a/_images/inheritance-6d04e2f32ae30ecc51861ea4f49f3a7545725ebe.png.map b/_images/inheritance-6d04e2f32ae30ecc51861ea4f49f3a7545725ebe.png.map new file mode 100644 index 000000000..71c90c6d0 --- /dev/null +++ b/_images/inheritance-6d04e2f32ae30ecc51861ea4f49f3a7545725ebe.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-6dd0f259143557785fbca66ea6b4d3428a8ba080.png b/_images/inheritance-6dd0f259143557785fbca66ea6b4d3428a8ba080.png new file mode 100644 index 000000000..2ef487241 Binary files /dev/null and b/_images/inheritance-6dd0f259143557785fbca66ea6b4d3428a8ba080.png differ diff --git a/_images/inheritance-6dd0f259143557785fbca66ea6b4d3428a8ba080.png.map b/_images/inheritance-6dd0f259143557785fbca66ea6b4d3428a8ba080.png.map new file mode 100644 index 000000000..87c731468 --- /dev/null +++ b/_images/inheritance-6dd0f259143557785fbca66ea6b4d3428a8ba080.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-6f38aef6aff42c4e17329e93d0cc358a2fab7dc6.png b/_images/inheritance-6f38aef6aff42c4e17329e93d0cc358a2fab7dc6.png new file mode 100644 index 000000000..b2a0ba8b1 Binary files /dev/null and b/_images/inheritance-6f38aef6aff42c4e17329e93d0cc358a2fab7dc6.png differ diff --git a/_images/inheritance-6f38aef6aff42c4e17329e93d0cc358a2fab7dc6.png.map b/_images/inheritance-6f38aef6aff42c4e17329e93d0cc358a2fab7dc6.png.map new file mode 100644 index 000000000..3e3fe0958 --- /dev/null +++ b/_images/inheritance-6f38aef6aff42c4e17329e93d0cc358a2fab7dc6.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-71761623e056b5c67611f39cf2149df7bbc10810.png b/_images/inheritance-71761623e056b5c67611f39cf2149df7bbc10810.png new file mode 100644 index 000000000..2818ed19b Binary files /dev/null and b/_images/inheritance-71761623e056b5c67611f39cf2149df7bbc10810.png differ diff --git a/_images/inheritance-71761623e056b5c67611f39cf2149df7bbc10810.png.map b/_images/inheritance-71761623e056b5c67611f39cf2149df7bbc10810.png.map new file mode 100644 index 000000000..f53a5ce95 --- /dev/null +++ b/_images/inheritance-71761623e056b5c67611f39cf2149df7bbc10810.png.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-727a0b8f61e203da33767e11d598965cb8fea4f3.png b/_images/inheritance-727a0b8f61e203da33767e11d598965cb8fea4f3.png new file mode 100644 index 000000000..889af21e4 Binary files /dev/null and b/_images/inheritance-727a0b8f61e203da33767e11d598965cb8fea4f3.png differ diff --git a/_images/inheritance-727a0b8f61e203da33767e11d598965cb8fea4f3.png.map b/_images/inheritance-727a0b8f61e203da33767e11d598965cb8fea4f3.png.map new file mode 100644 index 000000000..bd178c0bc --- /dev/null +++ b/_images/inheritance-727a0b8f61e203da33767e11d598965cb8fea4f3.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-76fe74067bb3fbf8235ab6333d0c51bdeae2cbf3.png b/_images/inheritance-76fe74067bb3fbf8235ab6333d0c51bdeae2cbf3.png new file mode 100644 index 000000000..ba6903a50 Binary files /dev/null and b/_images/inheritance-76fe74067bb3fbf8235ab6333d0c51bdeae2cbf3.png differ diff --git a/_images/inheritance-76fe74067bb3fbf8235ab6333d0c51bdeae2cbf3.png.map b/_images/inheritance-76fe74067bb3fbf8235ab6333d0c51bdeae2cbf3.png.map new file mode 100644 index 000000000..4e02b11ea --- /dev/null +++ b/_images/inheritance-76fe74067bb3fbf8235ab6333d0c51bdeae2cbf3.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-7b546dbe06f69dcd6bb68ca3d797f8395b44355d.png b/_images/inheritance-7b546dbe06f69dcd6bb68ca3d797f8395b44355d.png new file mode 100644 index 000000000..2818ed19b Binary files /dev/null and b/_images/inheritance-7b546dbe06f69dcd6bb68ca3d797f8395b44355d.png differ diff --git a/_images/inheritance-7b546dbe06f69dcd6bb68ca3d797f8395b44355d.png.map b/_images/inheritance-7b546dbe06f69dcd6bb68ca3d797f8395b44355d.png.map new file mode 100644 index 000000000..5a72cc5be --- /dev/null +++ b/_images/inheritance-7b546dbe06f69dcd6bb68ca3d797f8395b44355d.png.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-7fd05a93ebf60341074ba8933ba7faa3207765ff.png b/_images/inheritance-7fd05a93ebf60341074ba8933ba7faa3207765ff.png new file mode 100644 index 000000000..b88c998c2 Binary files /dev/null and b/_images/inheritance-7fd05a93ebf60341074ba8933ba7faa3207765ff.png differ diff --git a/_images/inheritance-7fd05a93ebf60341074ba8933ba7faa3207765ff.png.map b/_images/inheritance-7fd05a93ebf60341074ba8933ba7faa3207765ff.png.map new file mode 100644 index 000000000..755e96f13 --- /dev/null +++ b/_images/inheritance-7fd05a93ebf60341074ba8933ba7faa3207765ff.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-7fea55a9b6be5f4e419a54ac75b241d4015d849b.png b/_images/inheritance-7fea55a9b6be5f4e419a54ac75b241d4015d849b.png new file mode 100644 index 000000000..f98727647 Binary files /dev/null and b/_images/inheritance-7fea55a9b6be5f4e419a54ac75b241d4015d849b.png differ diff --git a/_images/inheritance-7fea55a9b6be5f4e419a54ac75b241d4015d849b.png.map b/_images/inheritance-7fea55a9b6be5f4e419a54ac75b241d4015d849b.png.map new file mode 100644 index 000000000..b74281695 --- /dev/null +++ b/_images/inheritance-7fea55a9b6be5f4e419a54ac75b241d4015d849b.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-809220ff255c247bf3575e9051c115bd32d4ebcf.png b/_images/inheritance-809220ff255c247bf3575e9051c115bd32d4ebcf.png new file mode 100644 index 000000000..e2640949e Binary files /dev/null and b/_images/inheritance-809220ff255c247bf3575e9051c115bd32d4ebcf.png differ diff --git a/_images/inheritance-809220ff255c247bf3575e9051c115bd32d4ebcf.png.map b/_images/inheritance-809220ff255c247bf3575e9051c115bd32d4ebcf.png.map new file mode 100644 index 000000000..8a188d2b5 --- /dev/null +++ b/_images/inheritance-809220ff255c247bf3575e9051c115bd32d4ebcf.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-80e6d9ec350fa57ace5bcdeaff5c621c5e18f543.png b/_images/inheritance-80e6d9ec350fa57ace5bcdeaff5c621c5e18f543.png new file mode 100644 index 000000000..f37f7e64b Binary files /dev/null and b/_images/inheritance-80e6d9ec350fa57ace5bcdeaff5c621c5e18f543.png differ diff --git a/_images/inheritance-80e6d9ec350fa57ace5bcdeaff5c621c5e18f543.png.map b/_images/inheritance-80e6d9ec350fa57ace5bcdeaff5c621c5e18f543.png.map new file mode 100644 index 000000000..55dc183e2 --- /dev/null +++ b/_images/inheritance-80e6d9ec350fa57ace5bcdeaff5c621c5e18f543.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-82e2c428f639f43568099adce2c4b165ceeec7e1.png b/_images/inheritance-82e2c428f639f43568099adce2c4b165ceeec7e1.png new file mode 100644 index 000000000..a8b2976b6 Binary files /dev/null and b/_images/inheritance-82e2c428f639f43568099adce2c4b165ceeec7e1.png differ diff --git a/_images/inheritance-82e2c428f639f43568099adce2c4b165ceeec7e1.png.map b/_images/inheritance-82e2c428f639f43568099adce2c4b165ceeec7e1.png.map new file mode 100644 index 000000000..82d1dc085 --- /dev/null +++ b/_images/inheritance-82e2c428f639f43568099adce2c4b165ceeec7e1.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-849267005e07f2f10e02e2a4bda80ae823988e56.png b/_images/inheritance-849267005e07f2f10e02e2a4bda80ae823988e56.png new file mode 100644 index 000000000..81f45e26f Binary files /dev/null and b/_images/inheritance-849267005e07f2f10e02e2a4bda80ae823988e56.png differ diff --git a/_images/inheritance-849267005e07f2f10e02e2a4bda80ae823988e56.png.map b/_images/inheritance-849267005e07f2f10e02e2a4bda80ae823988e56.png.map new file mode 100644 index 000000000..644286d55 --- /dev/null +++ b/_images/inheritance-849267005e07f2f10e02e2a4bda80ae823988e56.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-84e311b0fe2c01da3a4653454648a1a587c7aa2f.png b/_images/inheritance-84e311b0fe2c01da3a4653454648a1a587c7aa2f.png new file mode 100644 index 000000000..56d617963 Binary files /dev/null and b/_images/inheritance-84e311b0fe2c01da3a4653454648a1a587c7aa2f.png differ diff --git a/_images/inheritance-84e311b0fe2c01da3a4653454648a1a587c7aa2f.png.map b/_images/inheritance-84e311b0fe2c01da3a4653454648a1a587c7aa2f.png.map new file mode 100644 index 000000000..e4625c412 --- /dev/null +++ b/_images/inheritance-84e311b0fe2c01da3a4653454648a1a587c7aa2f.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-855f1539d8b036ed518bdefb962af87682dce603.png b/_images/inheritance-855f1539d8b036ed518bdefb962af87682dce603.png new file mode 100644 index 000000000..3aa9e9521 Binary files /dev/null and b/_images/inheritance-855f1539d8b036ed518bdefb962af87682dce603.png differ diff --git a/_images/inheritance-855f1539d8b036ed518bdefb962af87682dce603.png.map b/_images/inheritance-855f1539d8b036ed518bdefb962af87682dce603.png.map new file mode 100644 index 000000000..ca992ebb7 --- /dev/null +++ b/_images/inheritance-855f1539d8b036ed518bdefb962af87682dce603.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-85babdf40ded5a3fec13e444dff224d8d5b9348a.png b/_images/inheritance-85babdf40ded5a3fec13e444dff224d8d5b9348a.png new file mode 100644 index 000000000..83c2b9c74 Binary files /dev/null and b/_images/inheritance-85babdf40ded5a3fec13e444dff224d8d5b9348a.png differ diff --git a/_images/inheritance-85babdf40ded5a3fec13e444dff224d8d5b9348a.png.map b/_images/inheritance-85babdf40ded5a3fec13e444dff224d8d5b9348a.png.map new file mode 100644 index 000000000..77d27f6b8 --- /dev/null +++ b/_images/inheritance-85babdf40ded5a3fec13e444dff224d8d5b9348a.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-871315c60779332d6d75ef06c703d12c4b4c939b.png b/_images/inheritance-871315c60779332d6d75ef06c703d12c4b4c939b.png new file mode 100644 index 000000000..7526337c5 Binary files /dev/null and b/_images/inheritance-871315c60779332d6d75ef06c703d12c4b4c939b.png differ diff --git a/_images/inheritance-871315c60779332d6d75ef06c703d12c4b4c939b.png.map b/_images/inheritance-871315c60779332d6d75ef06c703d12c4b4c939b.png.map new file mode 100644 index 000000000..1ca1756f8 --- /dev/null +++ b/_images/inheritance-871315c60779332d6d75ef06c703d12c4b4c939b.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-88e5aeeae28777a5b3ad68a39a400a5a8b2b5c06.png b/_images/inheritance-88e5aeeae28777a5b3ad68a39a400a5a8b2b5c06.png new file mode 100644 index 000000000..8766c6107 Binary files /dev/null and b/_images/inheritance-88e5aeeae28777a5b3ad68a39a400a5a8b2b5c06.png differ diff --git a/_images/inheritance-88e5aeeae28777a5b3ad68a39a400a5a8b2b5c06.png.map b/_images/inheritance-88e5aeeae28777a5b3ad68a39a400a5a8b2b5c06.png.map new file mode 100644 index 000000000..ba2c51bef --- /dev/null +++ b/_images/inheritance-88e5aeeae28777a5b3ad68a39a400a5a8b2b5c06.png.map @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-8c5821a5cafc409557b9a336c8e4ca5f127adf83.png b/_images/inheritance-8c5821a5cafc409557b9a336c8e4ca5f127adf83.png new file mode 100644 index 000000000..44b7283cd Binary files /dev/null and b/_images/inheritance-8c5821a5cafc409557b9a336c8e4ca5f127adf83.png differ diff --git a/_images/inheritance-8c5821a5cafc409557b9a336c8e4ca5f127adf83.png.map b/_images/inheritance-8c5821a5cafc409557b9a336c8e4ca5f127adf83.png.map new file mode 100644 index 000000000..e580e850b --- /dev/null +++ b/_images/inheritance-8c5821a5cafc409557b9a336c8e4ca5f127adf83.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-8fbd5dbe43a2287bde88a5a9df9924bf5a370fb9.png b/_images/inheritance-8fbd5dbe43a2287bde88a5a9df9924bf5a370fb9.png new file mode 100644 index 000000000..5789c5b6a Binary files /dev/null and b/_images/inheritance-8fbd5dbe43a2287bde88a5a9df9924bf5a370fb9.png differ diff --git a/_images/inheritance-8fbd5dbe43a2287bde88a5a9df9924bf5a370fb9.png.map b/_images/inheritance-8fbd5dbe43a2287bde88a5a9df9924bf5a370fb9.png.map new file mode 100644 index 000000000..5c0305bba --- /dev/null +++ b/_images/inheritance-8fbd5dbe43a2287bde88a5a9df9924bf5a370fb9.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-94e3d3bcc1f8af1f8f7621675ce6746fcf198845.png b/_images/inheritance-94e3d3bcc1f8af1f8f7621675ce6746fcf198845.png new file mode 100644 index 000000000..8811b18c8 Binary files /dev/null and b/_images/inheritance-94e3d3bcc1f8af1f8f7621675ce6746fcf198845.png differ diff --git a/_images/inheritance-94e3d3bcc1f8af1f8f7621675ce6746fcf198845.png.map b/_images/inheritance-94e3d3bcc1f8af1f8f7621675ce6746fcf198845.png.map new file mode 100644 index 000000000..71640e124 --- /dev/null +++ b/_images/inheritance-94e3d3bcc1f8af1f8f7621675ce6746fcf198845.png.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-961fc3314a926195b8672558091b900cf8356960.png b/_images/inheritance-961fc3314a926195b8672558091b900cf8356960.png new file mode 100644 index 000000000..3b40b51af Binary files /dev/null and b/_images/inheritance-961fc3314a926195b8672558091b900cf8356960.png differ diff --git a/_images/inheritance-961fc3314a926195b8672558091b900cf8356960.png.map b/_images/inheritance-961fc3314a926195b8672558091b900cf8356960.png.map new file mode 100644 index 000000000..ed5c50402 --- /dev/null +++ b/_images/inheritance-961fc3314a926195b8672558091b900cf8356960.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-983290c749fd541553750450b12adc31bb755672.png b/_images/inheritance-983290c749fd541553750450b12adc31bb755672.png new file mode 100644 index 000000000..1c9d7751a Binary files /dev/null and b/_images/inheritance-983290c749fd541553750450b12adc31bb755672.png differ diff --git a/_images/inheritance-983290c749fd541553750450b12adc31bb755672.png.map b/_images/inheritance-983290c749fd541553750450b12adc31bb755672.png.map new file mode 100644 index 000000000..12317c913 --- /dev/null +++ b/_images/inheritance-983290c749fd541553750450b12adc31bb755672.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-9a4debe443c187a5fae622155b4676c0a8fed718.png b/_images/inheritance-9a4debe443c187a5fae622155b4676c0a8fed718.png new file mode 100644 index 000000000..cbcae0d79 Binary files /dev/null and b/_images/inheritance-9a4debe443c187a5fae622155b4676c0a8fed718.png differ diff --git a/_images/inheritance-9a4debe443c187a5fae622155b4676c0a8fed718.png.map b/_images/inheritance-9a4debe443c187a5fae622155b4676c0a8fed718.png.map new file mode 100644 index 000000000..1475bb447 --- /dev/null +++ b/_images/inheritance-9a4debe443c187a5fae622155b4676c0a8fed718.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-9a9a396abde0e7d5dbfbb1c6caf5a5c9cabc7cc6.png b/_images/inheritance-9a9a396abde0e7d5dbfbb1c6caf5a5c9cabc7cc6.png new file mode 100644 index 000000000..58966c87b Binary files /dev/null and b/_images/inheritance-9a9a396abde0e7d5dbfbb1c6caf5a5c9cabc7cc6.png differ diff --git a/_images/inheritance-9a9a396abde0e7d5dbfbb1c6caf5a5c9cabc7cc6.png.map b/_images/inheritance-9a9a396abde0e7d5dbfbb1c6caf5a5c9cabc7cc6.png.map new file mode 100644 index 000000000..b759f3726 --- /dev/null +++ b/_images/inheritance-9a9a396abde0e7d5dbfbb1c6caf5a5c9cabc7cc6.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-9dafa87d51dfdce580d6fb9c4907ceb756f7ae28.png b/_images/inheritance-9dafa87d51dfdce580d6fb9c4907ceb756f7ae28.png new file mode 100644 index 000000000..11b6b7c0f Binary files /dev/null and b/_images/inheritance-9dafa87d51dfdce580d6fb9c4907ceb756f7ae28.png differ diff --git a/_images/inheritance-9dafa87d51dfdce580d6fb9c4907ceb756f7ae28.png.map b/_images/inheritance-9dafa87d51dfdce580d6fb9c4907ceb756f7ae28.png.map new file mode 100644 index 000000000..3929f7181 --- /dev/null +++ b/_images/inheritance-9dafa87d51dfdce580d6fb9c4907ceb756f7ae28.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-a283c42bc3689fcd156bd26b57b2008280ac6642.png b/_images/inheritance-a283c42bc3689fcd156bd26b57b2008280ac6642.png new file mode 100644 index 000000000..2ee6468d4 Binary files /dev/null and b/_images/inheritance-a283c42bc3689fcd156bd26b57b2008280ac6642.png differ diff --git a/_images/inheritance-a283c42bc3689fcd156bd26b57b2008280ac6642.png.map b/_images/inheritance-a283c42bc3689fcd156bd26b57b2008280ac6642.png.map new file mode 100644 index 000000000..4dc12be5a --- /dev/null +++ b/_images/inheritance-a283c42bc3689fcd156bd26b57b2008280ac6642.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-a2a76eb8b4dc32739b507a18edb5a4f3d3f59d4f.png b/_images/inheritance-a2a76eb8b4dc32739b507a18edb5a4f3d3f59d4f.png new file mode 100644 index 000000000..c8745d554 Binary files /dev/null and b/_images/inheritance-a2a76eb8b4dc32739b507a18edb5a4f3d3f59d4f.png differ diff --git a/_images/inheritance-a2a76eb8b4dc32739b507a18edb5a4f3d3f59d4f.png.map b/_images/inheritance-a2a76eb8b4dc32739b507a18edb5a4f3d3f59d4f.png.map new file mode 100644 index 000000000..6f8ec45d3 --- /dev/null +++ b/_images/inheritance-a2a76eb8b4dc32739b507a18edb5a4f3d3f59d4f.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-a613788bca4c042c090a8af0f8fc90fa6351dd07.png b/_images/inheritance-a613788bca4c042c090a8af0f8fc90fa6351dd07.png new file mode 100644 index 000000000..39468697b Binary files /dev/null and b/_images/inheritance-a613788bca4c042c090a8af0f8fc90fa6351dd07.png differ diff --git a/_images/inheritance-a613788bca4c042c090a8af0f8fc90fa6351dd07.png.map b/_images/inheritance-a613788bca4c042c090a8af0f8fc90fa6351dd07.png.map new file mode 100644 index 000000000..5d0d94096 --- /dev/null +++ b/_images/inheritance-a613788bca4c042c090a8af0f8fc90fa6351dd07.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-a844d8881a6db8dfa3084e1fa96ae8653e96a662.png b/_images/inheritance-a844d8881a6db8dfa3084e1fa96ae8653e96a662.png new file mode 100644 index 000000000..8699538ed Binary files /dev/null and b/_images/inheritance-a844d8881a6db8dfa3084e1fa96ae8653e96a662.png differ diff --git a/_images/inheritance-a844d8881a6db8dfa3084e1fa96ae8653e96a662.png.map b/_images/inheritance-a844d8881a6db8dfa3084e1fa96ae8653e96a662.png.map new file mode 100644 index 000000000..75959f237 --- /dev/null +++ b/_images/inheritance-a844d8881a6db8dfa3084e1fa96ae8653e96a662.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-ae5926232c64c6c07d22854842483f187445a5d6.png b/_images/inheritance-ae5926232c64c6c07d22854842483f187445a5d6.png new file mode 100644 index 000000000..76ffcb14b Binary files /dev/null and b/_images/inheritance-ae5926232c64c6c07d22854842483f187445a5d6.png differ diff --git a/_images/inheritance-ae5926232c64c6c07d22854842483f187445a5d6.png.map b/_images/inheritance-ae5926232c64c6c07d22854842483f187445a5d6.png.map new file mode 100644 index 000000000..fb80068d9 --- /dev/null +++ b/_images/inheritance-ae5926232c64c6c07d22854842483f187445a5d6.png.map @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-ae6e499823209e9a7be458c466a92ba02d755f9d.png b/_images/inheritance-ae6e499823209e9a7be458c466a92ba02d755f9d.png new file mode 100644 index 000000000..9eb748458 Binary files /dev/null and b/_images/inheritance-ae6e499823209e9a7be458c466a92ba02d755f9d.png differ diff --git a/_images/inheritance-ae6e499823209e9a7be458c466a92ba02d755f9d.png.map b/_images/inheritance-ae6e499823209e9a7be458c466a92ba02d755f9d.png.map new file mode 100644 index 000000000..a7341ec80 --- /dev/null +++ b/_images/inheritance-ae6e499823209e9a7be458c466a92ba02d755f9d.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-ae985cb43fd6b441d10f259a2d6beb58bc7fe438.png b/_images/inheritance-ae985cb43fd6b441d10f259a2d6beb58bc7fe438.png new file mode 100644 index 000000000..ea54efc7e Binary files /dev/null and b/_images/inheritance-ae985cb43fd6b441d10f259a2d6beb58bc7fe438.png differ diff --git a/_images/inheritance-ae985cb43fd6b441d10f259a2d6beb58bc7fe438.png.map b/_images/inheritance-ae985cb43fd6b441d10f259a2d6beb58bc7fe438.png.map new file mode 100644 index 000000000..392d4586c --- /dev/null +++ b/_images/inheritance-ae985cb43fd6b441d10f259a2d6beb58bc7fe438.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-af4b382e45c5aca67b62d6d12860c02383b71cf7.png b/_images/inheritance-af4b382e45c5aca67b62d6d12860c02383b71cf7.png new file mode 100644 index 000000000..7249252f7 Binary files /dev/null and b/_images/inheritance-af4b382e45c5aca67b62d6d12860c02383b71cf7.png differ diff --git a/_images/inheritance-af4b382e45c5aca67b62d6d12860c02383b71cf7.png.map b/_images/inheritance-af4b382e45c5aca67b62d6d12860c02383b71cf7.png.map new file mode 100644 index 000000000..6276cd0b6 --- /dev/null +++ b/_images/inheritance-af4b382e45c5aca67b62d6d12860c02383b71cf7.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-afa6cd1c18cb7c4afa3a8c3cf552f1e4520773f4.png b/_images/inheritance-afa6cd1c18cb7c4afa3a8c3cf552f1e4520773f4.png new file mode 100644 index 000000000..c741435b6 Binary files /dev/null and b/_images/inheritance-afa6cd1c18cb7c4afa3a8c3cf552f1e4520773f4.png differ diff --git a/_images/inheritance-afa6cd1c18cb7c4afa3a8c3cf552f1e4520773f4.png.map b/_images/inheritance-afa6cd1c18cb7c4afa3a8c3cf552f1e4520773f4.png.map new file mode 100644 index 000000000..72e217845 --- /dev/null +++ b/_images/inheritance-afa6cd1c18cb7c4afa3a8c3cf552f1e4520773f4.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-b122c8baa6fb0770325ee3d186b2cb5f66065066.png b/_images/inheritance-b122c8baa6fb0770325ee3d186b2cb5f66065066.png new file mode 100644 index 000000000..e00b21595 Binary files /dev/null and b/_images/inheritance-b122c8baa6fb0770325ee3d186b2cb5f66065066.png differ diff --git a/_images/inheritance-b122c8baa6fb0770325ee3d186b2cb5f66065066.png.map b/_images/inheritance-b122c8baa6fb0770325ee3d186b2cb5f66065066.png.map new file mode 100644 index 000000000..909353eec --- /dev/null +++ b/_images/inheritance-b122c8baa6fb0770325ee3d186b2cb5f66065066.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-b2ba417fa1e2b4e04a9fc8b6e862947b25b1cf6f.png b/_images/inheritance-b2ba417fa1e2b4e04a9fc8b6e862947b25b1cf6f.png new file mode 100644 index 000000000..319e56e35 Binary files /dev/null and b/_images/inheritance-b2ba417fa1e2b4e04a9fc8b6e862947b25b1cf6f.png differ diff --git a/_images/inheritance-b2ba417fa1e2b4e04a9fc8b6e862947b25b1cf6f.png.map b/_images/inheritance-b2ba417fa1e2b4e04a9fc8b6e862947b25b1cf6f.png.map new file mode 100644 index 000000000..9f5720842 --- /dev/null +++ b/_images/inheritance-b2ba417fa1e2b4e04a9fc8b6e862947b25b1cf6f.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-b5615ba3d27365087c95d08ac946e474f2fac6e5.png b/_images/inheritance-b5615ba3d27365087c95d08ac946e474f2fac6e5.png new file mode 100644 index 000000000..98cd423a7 Binary files /dev/null and b/_images/inheritance-b5615ba3d27365087c95d08ac946e474f2fac6e5.png differ diff --git a/_images/inheritance-b5615ba3d27365087c95d08ac946e474f2fac6e5.png.map b/_images/inheritance-b5615ba3d27365087c95d08ac946e474f2fac6e5.png.map new file mode 100644 index 000000000..6d7f91742 --- /dev/null +++ b/_images/inheritance-b5615ba3d27365087c95d08ac946e474f2fac6e5.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-b5fea8f1ece0848f2f12d14e1897581be18cd3b0.png b/_images/inheritance-b5fea8f1ece0848f2f12d14e1897581be18cd3b0.png new file mode 100644 index 000000000..c9fe3926e Binary files /dev/null and b/_images/inheritance-b5fea8f1ece0848f2f12d14e1897581be18cd3b0.png differ diff --git a/_images/inheritance-b5fea8f1ece0848f2f12d14e1897581be18cd3b0.png.map b/_images/inheritance-b5fea8f1ece0848f2f12d14e1897581be18cd3b0.png.map new file mode 100644 index 000000000..c5c0acb4e --- /dev/null +++ b/_images/inheritance-b5fea8f1ece0848f2f12d14e1897581be18cd3b0.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-bbbe9eb93d81b5e4b44871cf2cdf31b014b917dd.png b/_images/inheritance-bbbe9eb93d81b5e4b44871cf2cdf31b014b917dd.png new file mode 100644 index 000000000..fb6fada40 Binary files /dev/null and b/_images/inheritance-bbbe9eb93d81b5e4b44871cf2cdf31b014b917dd.png differ diff --git a/_images/inheritance-bbbe9eb93d81b5e4b44871cf2cdf31b014b917dd.png.map b/_images/inheritance-bbbe9eb93d81b5e4b44871cf2cdf31b014b917dd.png.map new file mode 100644 index 000000000..5f0d9762f --- /dev/null +++ b/_images/inheritance-bbbe9eb93d81b5e4b44871cf2cdf31b014b917dd.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-c2a4ddabe8eb195d113231b179907fa1615902f1.png b/_images/inheritance-c2a4ddabe8eb195d113231b179907fa1615902f1.png new file mode 100644 index 000000000..99e8f26e2 Binary files /dev/null and b/_images/inheritance-c2a4ddabe8eb195d113231b179907fa1615902f1.png differ diff --git a/_images/inheritance-c2a4ddabe8eb195d113231b179907fa1615902f1.png.map b/_images/inheritance-c2a4ddabe8eb195d113231b179907fa1615902f1.png.map new file mode 100644 index 000000000..daf2a0d6c --- /dev/null +++ b/_images/inheritance-c2a4ddabe8eb195d113231b179907fa1615902f1.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-c353fecf8f675a68959a25ba0ebc6af8f2e4720c.png b/_images/inheritance-c353fecf8f675a68959a25ba0ebc6af8f2e4720c.png new file mode 100644 index 000000000..6aee515e1 Binary files /dev/null and b/_images/inheritance-c353fecf8f675a68959a25ba0ebc6af8f2e4720c.png differ diff --git a/_images/inheritance-c353fecf8f675a68959a25ba0ebc6af8f2e4720c.png.map b/_images/inheritance-c353fecf8f675a68959a25ba0ebc6af8f2e4720c.png.map new file mode 100644 index 000000000..0ab055e02 --- /dev/null +++ b/_images/inheritance-c353fecf8f675a68959a25ba0ebc6af8f2e4720c.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-c3a07f39ef03f9d51bb0afac05dbfddf35a872f3.png b/_images/inheritance-c3a07f39ef03f9d51bb0afac05dbfddf35a872f3.png new file mode 100644 index 000000000..8e3bfa50a Binary files /dev/null and b/_images/inheritance-c3a07f39ef03f9d51bb0afac05dbfddf35a872f3.png differ diff --git a/_images/inheritance-c3a07f39ef03f9d51bb0afac05dbfddf35a872f3.png.map b/_images/inheritance-c3a07f39ef03f9d51bb0afac05dbfddf35a872f3.png.map new file mode 100644 index 000000000..0078e85b7 --- /dev/null +++ b/_images/inheritance-c3a07f39ef03f9d51bb0afac05dbfddf35a872f3.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-c67f331c6fcff3aab582e1437043252f4395fe3d.png b/_images/inheritance-c67f331c6fcff3aab582e1437043252f4395fe3d.png new file mode 100644 index 000000000..f58e2a352 Binary files /dev/null and b/_images/inheritance-c67f331c6fcff3aab582e1437043252f4395fe3d.png differ diff --git a/_images/inheritance-c67f331c6fcff3aab582e1437043252f4395fe3d.png.map b/_images/inheritance-c67f331c6fcff3aab582e1437043252f4395fe3d.png.map new file mode 100644 index 000000000..655002681 --- /dev/null +++ b/_images/inheritance-c67f331c6fcff3aab582e1437043252f4395fe3d.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-c70d0c1c4ea79c8c9d5255c707200c3458aad31d.png b/_images/inheritance-c70d0c1c4ea79c8c9d5255c707200c3458aad31d.png new file mode 100644 index 000000000..27124dfa3 Binary files /dev/null and b/_images/inheritance-c70d0c1c4ea79c8c9d5255c707200c3458aad31d.png differ diff --git a/_images/inheritance-c70d0c1c4ea79c8c9d5255c707200c3458aad31d.png.map b/_images/inheritance-c70d0c1c4ea79c8c9d5255c707200c3458aad31d.png.map new file mode 100644 index 000000000..02a371d58 --- /dev/null +++ b/_images/inheritance-c70d0c1c4ea79c8c9d5255c707200c3458aad31d.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-c76cc22c3e6ab1e5609970937e4fc851869f3dfc.png b/_images/inheritance-c76cc22c3e6ab1e5609970937e4fc851869f3dfc.png new file mode 100644 index 000000000..46fc1b30f Binary files /dev/null and b/_images/inheritance-c76cc22c3e6ab1e5609970937e4fc851869f3dfc.png differ diff --git a/_images/inheritance-c76cc22c3e6ab1e5609970937e4fc851869f3dfc.png.map b/_images/inheritance-c76cc22c3e6ab1e5609970937e4fc851869f3dfc.png.map new file mode 100644 index 000000000..b5d2d2a96 --- /dev/null +++ b/_images/inheritance-c76cc22c3e6ab1e5609970937e4fc851869f3dfc.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-c9dd15499c887cad01b56fc643cfd38601574016.png b/_images/inheritance-c9dd15499c887cad01b56fc643cfd38601574016.png new file mode 100644 index 000000000..8a80f19f3 Binary files /dev/null and b/_images/inheritance-c9dd15499c887cad01b56fc643cfd38601574016.png differ diff --git a/_images/inheritance-c9dd15499c887cad01b56fc643cfd38601574016.png.map b/_images/inheritance-c9dd15499c887cad01b56fc643cfd38601574016.png.map new file mode 100644 index 000000000..5799fdaf3 --- /dev/null +++ b/_images/inheritance-c9dd15499c887cad01b56fc643cfd38601574016.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-caabd6515f40652e0de4037b7bfb36d46338415b.png b/_images/inheritance-caabd6515f40652e0de4037b7bfb36d46338415b.png new file mode 100644 index 000000000..152fbdb8f Binary files /dev/null and b/_images/inheritance-caabd6515f40652e0de4037b7bfb36d46338415b.png differ diff --git a/_images/inheritance-caabd6515f40652e0de4037b7bfb36d46338415b.png.map b/_images/inheritance-caabd6515f40652e0de4037b7bfb36d46338415b.png.map new file mode 100644 index 000000000..74f8c6d81 --- /dev/null +++ b/_images/inheritance-caabd6515f40652e0de4037b7bfb36d46338415b.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-cb7fa2ec65dffa6c2473c09f405783bfb420dd5d.png b/_images/inheritance-cb7fa2ec65dffa6c2473c09f405783bfb420dd5d.png new file mode 100644 index 000000000..f2e43585a Binary files /dev/null and b/_images/inheritance-cb7fa2ec65dffa6c2473c09f405783bfb420dd5d.png differ diff --git a/_images/inheritance-cb7fa2ec65dffa6c2473c09f405783bfb420dd5d.png.map b/_images/inheritance-cb7fa2ec65dffa6c2473c09f405783bfb420dd5d.png.map new file mode 100644 index 000000000..45a970c01 --- /dev/null +++ b/_images/inheritance-cb7fa2ec65dffa6c2473c09f405783bfb420dd5d.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-ce54851577643e31018cc4a3d45fd2665a7906fe.png b/_images/inheritance-ce54851577643e31018cc4a3d45fd2665a7906fe.png new file mode 100644 index 000000000..6b148a8cd Binary files /dev/null and b/_images/inheritance-ce54851577643e31018cc4a3d45fd2665a7906fe.png differ diff --git a/_images/inheritance-ce54851577643e31018cc4a3d45fd2665a7906fe.png.map b/_images/inheritance-ce54851577643e31018cc4a3d45fd2665a7906fe.png.map new file mode 100644 index 000000000..9dcb0159c --- /dev/null +++ b/_images/inheritance-ce54851577643e31018cc4a3d45fd2665a7906fe.png.map @@ -0,0 +1,3 @@ + + + diff --git a/_images/inheritance-d1767b8c682107f60746e1bce7dece86afaf84aa.png b/_images/inheritance-d1767b8c682107f60746e1bce7dece86afaf84aa.png new file mode 100644 index 000000000..eb34a6424 Binary files /dev/null and b/_images/inheritance-d1767b8c682107f60746e1bce7dece86afaf84aa.png differ diff --git a/_images/inheritance-d1767b8c682107f60746e1bce7dece86afaf84aa.png.map b/_images/inheritance-d1767b8c682107f60746e1bce7dece86afaf84aa.png.map new file mode 100644 index 000000000..b3aed4202 --- /dev/null +++ b/_images/inheritance-d1767b8c682107f60746e1bce7dece86afaf84aa.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-d62ea8cd3d85eaba5f6fb884061494298f62d87f.png b/_images/inheritance-d62ea8cd3d85eaba5f6fb884061494298f62d87f.png new file mode 100644 index 000000000..a7c31de0f Binary files /dev/null and b/_images/inheritance-d62ea8cd3d85eaba5f6fb884061494298f62d87f.png differ diff --git a/_images/inheritance-d62ea8cd3d85eaba5f6fb884061494298f62d87f.png.map b/_images/inheritance-d62ea8cd3d85eaba5f6fb884061494298f62d87f.png.map new file mode 100644 index 000000000..5627d825e --- /dev/null +++ b/_images/inheritance-d62ea8cd3d85eaba5f6fb884061494298f62d87f.png.map @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-d85849f6cdfeb2c7c4e0d3aa043f1e9ef6eaeb5d.png b/_images/inheritance-d85849f6cdfeb2c7c4e0d3aa043f1e9ef6eaeb5d.png new file mode 100644 index 000000000..cd8838f5e Binary files /dev/null and b/_images/inheritance-d85849f6cdfeb2c7c4e0d3aa043f1e9ef6eaeb5d.png differ diff --git a/_images/inheritance-d85849f6cdfeb2c7c4e0d3aa043f1e9ef6eaeb5d.png.map b/_images/inheritance-d85849f6cdfeb2c7c4e0d3aa043f1e9ef6eaeb5d.png.map new file mode 100644 index 000000000..dcdc44131 --- /dev/null +++ b/_images/inheritance-d85849f6cdfeb2c7c4e0d3aa043f1e9ef6eaeb5d.png.map @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/_images/inheritance-d861e5c0593b0543b8df440087a67bed65b77dba.png b/_images/inheritance-d861e5c0593b0543b8df440087a67bed65b77dba.png new file mode 100644 index 000000000..a7404f6d7 Binary files /dev/null and b/_images/inheritance-d861e5c0593b0543b8df440087a67bed65b77dba.png differ diff --git a/_images/inheritance-d861e5c0593b0543b8df440087a67bed65b77dba.png.map b/_images/inheritance-d861e5c0593b0543b8df440087a67bed65b77dba.png.map new file mode 100644 index 000000000..ea229b507 --- /dev/null +++ b/_images/inheritance-d861e5c0593b0543b8df440087a67bed65b77dba.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-dca0be0a699d1165150543b30273470581473ca6.png b/_images/inheritance-dca0be0a699d1165150543b30273470581473ca6.png new file mode 100644 index 000000000..ad0805ddf Binary files /dev/null and b/_images/inheritance-dca0be0a699d1165150543b30273470581473ca6.png differ diff --git a/_images/inheritance-dca0be0a699d1165150543b30273470581473ca6.png.map b/_images/inheritance-dca0be0a699d1165150543b30273470581473ca6.png.map new file mode 100644 index 000000000..b8ca76207 --- /dev/null +++ b/_images/inheritance-dca0be0a699d1165150543b30273470581473ca6.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-de0fda22c81f8f2d151b7c2e014a176b31f545f5.png b/_images/inheritance-de0fda22c81f8f2d151b7c2e014a176b31f545f5.png new file mode 100644 index 000000000..bcf6c251a Binary files /dev/null and b/_images/inheritance-de0fda22c81f8f2d151b7c2e014a176b31f545f5.png differ diff --git a/_images/inheritance-de0fda22c81f8f2d151b7c2e014a176b31f545f5.png.map b/_images/inheritance-de0fda22c81f8f2d151b7c2e014a176b31f545f5.png.map new file mode 100644 index 000000000..fdd5e39f9 --- /dev/null +++ b/_images/inheritance-de0fda22c81f8f2d151b7c2e014a176b31f545f5.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-df5d304858a45bb19176a7f397376fe27a24d5b0.png b/_images/inheritance-df5d304858a45bb19176a7f397376fe27a24d5b0.png new file mode 100644 index 000000000..75573f22e Binary files /dev/null and b/_images/inheritance-df5d304858a45bb19176a7f397376fe27a24d5b0.png differ diff --git a/_images/inheritance-df5d304858a45bb19176a7f397376fe27a24d5b0.png.map b/_images/inheritance-df5d304858a45bb19176a7f397376fe27a24d5b0.png.map new file mode 100644 index 000000000..160e3b4a5 --- /dev/null +++ b/_images/inheritance-df5d304858a45bb19176a7f397376fe27a24d5b0.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-e08dcebdc35c3c29fcc9539d1ede6ee20aa530f1.png b/_images/inheritance-e08dcebdc35c3c29fcc9539d1ede6ee20aa530f1.png new file mode 100644 index 000000000..c91247c0b Binary files /dev/null and b/_images/inheritance-e08dcebdc35c3c29fcc9539d1ede6ee20aa530f1.png differ diff --git a/_images/inheritance-e08dcebdc35c3c29fcc9539d1ede6ee20aa530f1.png.map b/_images/inheritance-e08dcebdc35c3c29fcc9539d1ede6ee20aa530f1.png.map new file mode 100644 index 000000000..e94f5e691 --- /dev/null +++ b/_images/inheritance-e08dcebdc35c3c29fcc9539d1ede6ee20aa530f1.png.map @@ -0,0 +1,6 @@ + + + + + + diff --git a/_images/inheritance-e1bdc0796a3217d7fef2eebb61d217c16814c8f3.png b/_images/inheritance-e1bdc0796a3217d7fef2eebb61d217c16814c8f3.png new file mode 100644 index 000000000..8e4336a0a Binary files /dev/null and b/_images/inheritance-e1bdc0796a3217d7fef2eebb61d217c16814c8f3.png differ diff --git a/_images/inheritance-e1bdc0796a3217d7fef2eebb61d217c16814c8f3.png.map b/_images/inheritance-e1bdc0796a3217d7fef2eebb61d217c16814c8f3.png.map new file mode 100644 index 000000000..40b955c69 --- /dev/null +++ b/_images/inheritance-e1bdc0796a3217d7fef2eebb61d217c16814c8f3.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-e4d5083cc58d2f42216d05e2df0667980797f195.png b/_images/inheritance-e4d5083cc58d2f42216d05e2df0667980797f195.png new file mode 100644 index 000000000..94a1d5ea1 Binary files /dev/null and b/_images/inheritance-e4d5083cc58d2f42216d05e2df0667980797f195.png differ diff --git a/_images/inheritance-e4d5083cc58d2f42216d05e2df0667980797f195.png.map b/_images/inheritance-e4d5083cc58d2f42216d05e2df0667980797f195.png.map new file mode 100644 index 000000000..c64af5fb2 --- /dev/null +++ b/_images/inheritance-e4d5083cc58d2f42216d05e2df0667980797f195.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-e6842f991e2de234982b0743e1469bced73377b5.png b/_images/inheritance-e6842f991e2de234982b0743e1469bced73377b5.png new file mode 100644 index 000000000..73337575c Binary files /dev/null and b/_images/inheritance-e6842f991e2de234982b0743e1469bced73377b5.png differ diff --git a/_images/inheritance-e6842f991e2de234982b0743e1469bced73377b5.png.map b/_images/inheritance-e6842f991e2de234982b0743e1469bced73377b5.png.map new file mode 100644 index 000000000..fd6dc3b85 --- /dev/null +++ b/_images/inheritance-e6842f991e2de234982b0743e1469bced73377b5.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-e772ed870725d86c4e771393b1dec23fa831453e.png b/_images/inheritance-e772ed870725d86c4e771393b1dec23fa831453e.png new file mode 100644 index 000000000..3d53fd846 Binary files /dev/null and b/_images/inheritance-e772ed870725d86c4e771393b1dec23fa831453e.png differ diff --git a/_images/inheritance-e772ed870725d86c4e771393b1dec23fa831453e.png.map b/_images/inheritance-e772ed870725d86c4e771393b1dec23fa831453e.png.map new file mode 100644 index 000000000..a05f3ffd0 --- /dev/null +++ b/_images/inheritance-e772ed870725d86c4e771393b1dec23fa831453e.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-e9d265955ad1689ddc8a1c594449a61b48855196.png b/_images/inheritance-e9d265955ad1689ddc8a1c594449a61b48855196.png new file mode 100644 index 000000000..094ea2961 Binary files /dev/null and b/_images/inheritance-e9d265955ad1689ddc8a1c594449a61b48855196.png differ diff --git a/_images/inheritance-e9d265955ad1689ddc8a1c594449a61b48855196.png.map b/_images/inheritance-e9d265955ad1689ddc8a1c594449a61b48855196.png.map new file mode 100644 index 000000000..60882f3ff --- /dev/null +++ b/_images/inheritance-e9d265955ad1689ddc8a1c594449a61b48855196.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-ed8469e1db5f0a117933bb5fb22199967039b8ce.png b/_images/inheritance-ed8469e1db5f0a117933bb5fb22199967039b8ce.png new file mode 100644 index 000000000..9d7942193 Binary files /dev/null and b/_images/inheritance-ed8469e1db5f0a117933bb5fb22199967039b8ce.png differ diff --git a/_images/inheritance-ed8469e1db5f0a117933bb5fb22199967039b8ce.png.map b/_images/inheritance-ed8469e1db5f0a117933bb5fb22199967039b8ce.png.map new file mode 100644 index 000000000..0c00d7e1d --- /dev/null +++ b/_images/inheritance-ed8469e1db5f0a117933bb5fb22199967039b8ce.png.map @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/_images/inheritance-eef556eadaaac0ad4910442ba4e8136e9ae1f04b.png b/_images/inheritance-eef556eadaaac0ad4910442ba4e8136e9ae1f04b.png new file mode 100644 index 000000000..e50e8ac82 Binary files /dev/null and b/_images/inheritance-eef556eadaaac0ad4910442ba4e8136e9ae1f04b.png differ diff --git a/_images/inheritance-eef556eadaaac0ad4910442ba4e8136e9ae1f04b.png.map b/_images/inheritance-eef556eadaaac0ad4910442ba4e8136e9ae1f04b.png.map new file mode 100644 index 000000000..cc279434f --- /dev/null +++ b/_images/inheritance-eef556eadaaac0ad4910442ba4e8136e9ae1f04b.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-efd08b64875b4b126526710699fe4e6b3c686f8f.png b/_images/inheritance-efd08b64875b4b126526710699fe4e6b3c686f8f.png new file mode 100644 index 000000000..93587de8f Binary files /dev/null and b/_images/inheritance-efd08b64875b4b126526710699fe4e6b3c686f8f.png differ diff --git a/_images/inheritance-efd08b64875b4b126526710699fe4e6b3c686f8f.png.map b/_images/inheritance-efd08b64875b4b126526710699fe4e6b3c686f8f.png.map new file mode 100644 index 000000000..e11a1d30a --- /dev/null +++ b/_images/inheritance-efd08b64875b4b126526710699fe4e6b3c686f8f.png.map @@ -0,0 +1,7 @@ + + + + + + + diff --git a/_images/inheritance-f003d9cf2727c5bb29e05a3c37d791ce02dc6524.png b/_images/inheritance-f003d9cf2727c5bb29e05a3c37d791ce02dc6524.png new file mode 100644 index 000000000..19b6340b0 Binary files /dev/null and b/_images/inheritance-f003d9cf2727c5bb29e05a3c37d791ce02dc6524.png differ diff --git a/_images/inheritance-f003d9cf2727c5bb29e05a3c37d791ce02dc6524.png.map b/_images/inheritance-f003d9cf2727c5bb29e05a3c37d791ce02dc6524.png.map new file mode 100644 index 000000000..8bec6d6dd --- /dev/null +++ b/_images/inheritance-f003d9cf2727c5bb29e05a3c37d791ce02dc6524.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-f10c84f45c575db97f6b1b7df7256fe41ff4f809.png b/_images/inheritance-f10c84f45c575db97f6b1b7df7256fe41ff4f809.png new file mode 100644 index 000000000..230af0c21 Binary files /dev/null and b/_images/inheritance-f10c84f45c575db97f6b1b7df7256fe41ff4f809.png differ diff --git a/_images/inheritance-f10c84f45c575db97f6b1b7df7256fe41ff4f809.png.map b/_images/inheritance-f10c84f45c575db97f6b1b7df7256fe41ff4f809.png.map new file mode 100644 index 000000000..8923593f7 --- /dev/null +++ b/_images/inheritance-f10c84f45c575db97f6b1b7df7256fe41ff4f809.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/inheritance-f188231e4969a9a75a7a51185354ad747688a465.png b/_images/inheritance-f188231e4969a9a75a7a51185354ad747688a465.png new file mode 100644 index 000000000..fb1f91703 Binary files /dev/null and b/_images/inheritance-f188231e4969a9a75a7a51185354ad747688a465.png differ diff --git a/_images/inheritance-f188231e4969a9a75a7a51185354ad747688a465.png.map b/_images/inheritance-f188231e4969a9a75a7a51185354ad747688a465.png.map new file mode 100644 index 000000000..afda5aeff --- /dev/null +++ b/_images/inheritance-f188231e4969a9a75a7a51185354ad747688a465.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-f41d8d18885ff9e43445161d3a677d03a86ee72f.png b/_images/inheritance-f41d8d18885ff9e43445161d3a677d03a86ee72f.png new file mode 100644 index 000000000..267574ffe Binary files /dev/null and b/_images/inheritance-f41d8d18885ff9e43445161d3a677d03a86ee72f.png differ diff --git a/_images/inheritance-f41d8d18885ff9e43445161d3a677d03a86ee72f.png.map b/_images/inheritance-f41d8d18885ff9e43445161d3a677d03a86ee72f.png.map new file mode 100644 index 000000000..c83627988 --- /dev/null +++ b/_images/inheritance-f41d8d18885ff9e43445161d3a677d03a86ee72f.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-f44d43913e3d26b5844c4756a309a8875e72ba17.png b/_images/inheritance-f44d43913e3d26b5844c4756a309a8875e72ba17.png new file mode 100644 index 000000000..8811b18c8 Binary files /dev/null and b/_images/inheritance-f44d43913e3d26b5844c4756a309a8875e72ba17.png differ diff --git a/_images/inheritance-f44d43913e3d26b5844c4756a309a8875e72ba17.png.map b/_images/inheritance-f44d43913e3d26b5844c4756a309a8875e72ba17.png.map new file mode 100644 index 000000000..b9d7acee1 --- /dev/null +++ b/_images/inheritance-f44d43913e3d26b5844c4756a309a8875e72ba17.png.map @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/_images/inheritance-f7ad9ce71b6fee6f7cb328e704be867309273ced.png b/_images/inheritance-f7ad9ce71b6fee6f7cb328e704be867309273ced.png new file mode 100644 index 000000000..702c0ede0 Binary files /dev/null and b/_images/inheritance-f7ad9ce71b6fee6f7cb328e704be867309273ced.png differ diff --git a/_images/inheritance-f7ad9ce71b6fee6f7cb328e704be867309273ced.png.map b/_images/inheritance-f7ad9ce71b6fee6f7cb328e704be867309273ced.png.map new file mode 100644 index 000000000..aee937357 --- /dev/null +++ b/_images/inheritance-f7ad9ce71b6fee6f7cb328e704be867309273ced.png.map @@ -0,0 +1,5 @@ + + + + + diff --git a/_images/inheritance-fa76a3513673b211a36943bc1da3f46eab96844f.png b/_images/inheritance-fa76a3513673b211a36943bc1da3f46eab96844f.png new file mode 100644 index 000000000..4aaed6688 Binary files /dev/null and b/_images/inheritance-fa76a3513673b211a36943bc1da3f46eab96844f.png differ diff --git a/_images/inheritance-fa76a3513673b211a36943bc1da3f46eab96844f.png.map b/_images/inheritance-fa76a3513673b211a36943bc1da3f46eab96844f.png.map new file mode 100644 index 000000000..49352eb39 --- /dev/null +++ b/_images/inheritance-fa76a3513673b211a36943bc1da3f46eab96844f.png.map @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/_images/inheritance-fd8fb0b239736cf89e8c70a5ab3a6f981f340f3f.png b/_images/inheritance-fd8fb0b239736cf89e8c70a5ab3a6f981f340f3f.png new file mode 100644 index 000000000..c4539fcfd Binary files /dev/null and b/_images/inheritance-fd8fb0b239736cf89e8c70a5ab3a6f981f340f3f.png differ diff --git a/_images/inheritance-fd8fb0b239736cf89e8c70a5ab3a6f981f340f3f.png.map b/_images/inheritance-fd8fb0b239736cf89e8c70a5ab3a6f981f340f3f.png.map new file mode 100644 index 000000000..ff1876d59 --- /dev/null +++ b/_images/inheritance-fd8fb0b239736cf89e8c70a5ab3a6f981f340f3f.png.map @@ -0,0 +1,4 @@ + + + + diff --git a/_images/viewephys.png b/_images/viewephys.png new file mode 100644 index 000000000..2a86dc176 Binary files /dev/null and b/_images/viewephys.png differ diff --git a/_images/xonar_labels.png b/_images/xonar_labels.png new file mode 100644 index 000000000..d08692dd1 Binary files /dev/null and b/_images/xonar_labels.png differ diff --git a/_modules/iblrig/base_choice_world.html b/_modules/iblrig/base_choice_world.html new file mode 100644 index 000000000..1213c54c3 --- /dev/null +++ b/_modules/iblrig/base_choice_world.html @@ -0,0 +1,1273 @@ + + + + + + iblrig.base_choice_world — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.base_choice_world

+"""Extends the base_tasks modules by providing task logic around the Choice World protocol."""
+
+import abc
+import logging
+import math
+import random
+import subprocess
+import time
+from pathlib import Path
+from string import ascii_letters
+from typing import Annotated, Any
+
+import numpy as np
+import pandas as pd
+from annotated_types import Interval, IsNan
+from pydantic import NonNegativeFloat, NonNegativeInt
+
+import iblrig.base_tasks
+import iblrig.graphic
+from iblrig import choiceworld, misc
+from iblrig.hardware import SOFTCODE
+from iblrig.pydantic_definitions import TrialDataModel
+from iblutil.io import jsonable
+from iblutil.util import Bunch
+from pybpodapi.com.messaging.trial import Trial
+from pybpodapi.protocol import StateMachine
+
+log = logging.getLogger(__name__)
+
+NTRIALS_INIT = 2000
+NBLOCKS_INIT = 100
+
+# TODO: task parameters should be verified through a pydantic model
+#
+# Probability = Annotated[float, Field(ge=0.0, le=1.0)]
+#
+# class ChoiceWorldParams(BaseModel):
+#     AUTOMATIC_CALIBRATION: bool = True
+#     ADAPTIVE_REWARD: bool = False
+#     BONSAI_EDITOR: bool = False
+#     CALIBRATION_VALUE: float = 0.067
+#     CONTRAST_SET: list[Probability] = Field([1.0, 0.25, 0.125, 0.0625, 0.0], min_length=1)
+#     CONTRAST_SET_PROBABILITY_TYPE: Literal['uniform', 'skew_zero'] = 'uniform'
+#     GO_TONE_AMPLITUDE: float = 0.0272
+#     GO_TONE_DURATION: float = 0.11
+#     GO_TONE_IDX: int = Field(2, ge=0)
+#     GO_TONE_FREQUENCY: float = Field(5000, gt=0)
+#     FEEDBACK_CORRECT_DELAY_SECS: float = 1
+#     FEEDBACK_ERROR_DELAY_SECS: float = 2
+#     FEEDBACK_NOGO_DELAY_SECS: float = 2
+#     INTERACTIVE_DELAY: float = 0.0
+#     ITI_DELAY_SECS: float = 0.5
+#     NTRIALS: int = Field(2000, gt=0)
+#     PROBABILITY_LEFT: Probability = 0.5
+#     QUIESCENCE_THRESHOLDS: list[float] = Field(default=[-2, 2], min_length=2, max_length=2)
+#     QUIESCENT_PERIOD: float = 0.2
+#     RECORD_AMBIENT_SENSOR_DATA: bool = True
+#     RECORD_SOUND: bool = True
+#     RESPONSE_WINDOW: float = 60
+#     REWARD_AMOUNT_UL: float = 1.5
+#     REWARD_TYPE: str = 'Water 10% Sucrose'
+#     STIM_ANGLE: float = 0.0
+#     STIM_FREQ: float = 0.1
+#     STIM_GAIN: float = 4.0  # wheel to stimulus relationship (degrees visual angle per mm of wheel displacement)
+#     STIM_POSITIONS: list[float] = [-35, 35]
+#     STIM_SIGMA: float = 7.0
+#     STIM_TRANSLATION_Z: Literal[7, 8] = 7  # 7 for ephys, 8 otherwise. -p:Stim.TranslationZ-{STIM_TRANSLATION_Z} bonsai param
+#     STIM_REVERSE: bool = False
+#     SYNC_SQUARE_X: float = 1.33
+#     SYNC_SQUARE_Y: float = -1.03
+#     USE_AUTOMATIC_STOPPING_CRITERIONS: bool = True
+#     VISUAL_STIMULUS: str = 'GaborIBLTask / Gabor2D.bonsai'  # null / passiveChoiceWorld_passive.bonsai
+#     WHITE_NOISE_AMPLITUDE: float = 0.05
+#     WHITE_NOISE_DURATION: float = 0.5
+#     WHITE_NOISE_IDX: int = 3
+
+
+
+[docs] +class ChoiceWorldTrialData(TrialDataModel): + """Pydantic Model for Trial Data.""" + + contrast: Annotated[float, Interval(ge=0.0, le=1.0)] + stim_probability_left: Annotated[float, Interval(ge=0.0, le=1.0)] + position: float + quiescent_period: NonNegativeFloat + reward_amount: NonNegativeFloat + reward_valve_time: NonNegativeFloat + stim_angle: Annotated[float, Interval(ge=-180.0, le=180.0)] + stim_freq: NonNegativeFloat + stim_gain: float + stim_phase: Annotated[float, Interval(ge=0.0, le=2 * math.pi)] + stim_reverse: bool + stim_sigma: float + trial_num: NonNegativeInt + pause_duration: NonNegativeFloat = 0.0 + + # The following variables are only used in ActiveChoiceWorld + # We keep them here with fixed default values for sake of compatibility + # + # TODO: Yes, this should probably be done differently. + response_side: Annotated[int, Interval(ge=0, le=0)] = 0 + response_time: IsNan[float] = np.nan + trial_correct: Annotated[bool, Interval(ge=0, le=0)] = False
+ + + +
+[docs] +class ChoiceWorldSession( + iblrig.base_tasks.BonsaiRecordingMixin, + iblrig.base_tasks.BonsaiVisualStimulusMixin, + iblrig.base_tasks.BpodMixin, + iblrig.base_tasks.Frame2TTLMixin, + iblrig.base_tasks.RotaryEncoderMixin, + iblrig.base_tasks.SoundMixin, + iblrig.base_tasks.ValveMixin, + iblrig.base_tasks.NetworkSession, +): + # task_params = ChoiceWorldParams() + base_parameters_file = Path(__file__).parent.joinpath('base_choice_world_params.yaml') + TrialDataModel = ChoiceWorldTrialData + +
+[docs] + def __init__(self, *args, delay_secs=0, **kwargs): + super().__init__(**kwargs) + self.task_params['SESSION_DELAY_START'] = delay_secs + # init behaviour data + self.movement_left = self.device_rotary_encoder.THRESHOLD_EVENTS[self.task_params.QUIESCENCE_THRESHOLDS[0]] + self.movement_right = self.device_rotary_encoder.THRESHOLD_EVENTS[self.task_params.QUIESCENCE_THRESHOLDS[1]] + # init counter variables + self.trial_num = -1 + self.block_num = -1 + self.block_trial_num = -1 + # init the tables, there are 2 of them: a trials table and a ambient sensor data table + self.trials_table = self.TrialDataModel.preallocate_dataframe(NTRIALS_INIT) + self.ambient_sensor_table = pd.DataFrame( + { + 'Temperature_C': np.zeros(NTRIALS_INIT) * np.NaN, + 'AirPressure_mb': np.zeros(NTRIALS_INIT) * np.NaN, + 'RelativeHumidity': np.zeros(NTRIALS_INIT) * np.NaN, + } + )
+ + +
+[docs] + @staticmethod + def extra_parser(): + """:return: argparse.parser()""" + parser = super(ChoiceWorldSession, ChoiceWorldSession).extra_parser() + parser.add_argument( + '--delay_secs', + dest='delay_secs', + default=0, + type=int, + required=False, + help='initial delay before starting the first trial (default: 0s)', + ) + parser.add_argument( + '--remote', + dest='remote_rigs', + type=str, + required=False, + action='append', + nargs='+', + help='specify one of the remote rigs to interact with over the network', + ) + return parser
+ + +
+[docs] + def start_hardware(self): + """ + In this step we explicitly run the start methods of the various mixins. + The super class start method is overloaded because we need to start the different hardware pieces in order + """ + if not self.is_mock: + self.start_mixin_frame2ttl() + self.start_mixin_bpod() + self.start_mixin_valve() + self.start_mixin_sound() + self.start_mixin_rotary_encoder() + self.start_mixin_bonsai_cameras() + self.start_mixin_bonsai_microphone() + self.start_mixin_bonsai_visual_stimulus() + self.bpod.register_softcodes(self.softcode_dictionary())
+ + + def _run(self): + """Run the task with the actual state machine.""" + time_last_trial_end = time.time() + for i in range(self.task_params.NTRIALS): # Main loop + # t_overhead = time.time() + self.next_trial() + log.info(f'Starting trial: {i}') + # ============================================================================= + # Start state machine definition + # ============================================================================= + sma = self.get_state_machine_trial(i) + log.debug('Sending state machine to bpod') + # Send state machine description to Bpod device + self.bpod.send_state_machine(sma) + # t_overhead = time.time() - t_overhead + # The ITI_DELAY_SECS defines the grey screen period within the state machine, where the + # Bpod TTL is HIGH. The DEAD_TIME param defines the time between last trial and the next + dead_time = self.task_params.get('DEAD_TIME', 0.5) + dt = self.task_params.ITI_DELAY_SECS - dead_time - (time.time() - time_last_trial_end) + # wait to achieve the desired ITI duration + if dt > 0: + time.sleep(dt) + # Run state machine + log.debug('running state machine') + self.bpod.run_state_machine(sma) # Locks until state machine 'exit' is reached + time_last_trial_end = time.time() + # handle pause event + flag_pause = self.paths.SESSION_FOLDER.joinpath('.pause') + flag_stop = self.paths.SESSION_FOLDER.joinpath('.stop') + if flag_pause.exists() and i < (self.task_params.NTRIALS - 1): + log.info(f'Pausing session inbetween trials {i} and {i + 1}') + while flag_pause.exists() and not flag_stop.exists(): + time.sleep(1) + self.trials_table.at[self.trial_num, 'pause_duration'] = time.time() - time_last_trial_end + if not flag_stop.exists(): + log.info('Resuming session') + + # save trial and update log + self.trial_completed(self.bpod.session.current_trial.export()) + self.ambient_sensor_table.loc[i] = self.bpod.get_ambient_sensor_reading() + self.show_trial_log() + + # handle stop event + if flag_stop.exists(): + log.info('Stopping session after trial %d', i) + flag_stop.unlink() + break + +
+[docs] + def mock(self, file_jsonable_fixture=None): + """ + Instantiate a state machine and Bpod object to simulate a task's run. + + This is useful to test or display the state machine flow. + """ + super().mock() + + if file_jsonable_fixture is not None: + task_data = jsonable.read(file_jsonable_fixture) + # pop-out the bpod data from the table + bpod_data = [] + for td in task_data: + bpod_data.append(td.pop('behavior_data')) + + class MockTrial(Trial): + def export(self): + return np.random.choice(bpod_data) + else: + + class MockTrial(Trial): + def export(self): + return {} + + self.bpod.session.trials = [MockTrial()] + self.bpod.send_state_machine = lambda k: None + self.bpod.run_state_machine = lambda k: time.sleep(1.2) + + daction = ('dummy', 'action') + self.sound = Bunch({'GO_TONE': daction, 'WHITE_NOISE': daction}) + + self.bpod.actions.update( + { + 'play_tone': daction, + 'play_noise': daction, + 'stop_sound': daction, + 'rotary_encoder_reset': daction, + 'bonsai_hide_stim': daction, + 'bonsai_show_stim': daction, + 'bonsai_closed_loop': daction, + 'bonsai_freeze_stim': daction, + 'bonsai_show_center': daction, + } + )
+ + +
+[docs] + def get_graphviz_task(self, output_file=None, view=True): + """ + Get the state machine's states diagram in Digraph format. + + :param output_file: + :return: + """ + import graphviz + + self.next_trial() + sma = self.get_state_machine_trial(0) + if sma is None: + return + states_indices = {i: k for i, k in enumerate(sma.state_names)} + states_indices.update({(i + 10000): k for i, k in enumerate(sma.undeclared)}) + states_letters = {k: ascii_letters[i] for i, k in enumerate(sma.state_names)} + dot = graphviz.Digraph(comment='The Great IBL Task') + edges = [] + + for i in range(len(sma.state_names)): + letter = states_letters[sma.state_names[i]] + dot.node(letter, sma.state_names[i]) + if ~np.isnan(sma.state_timer_matrix[i]): + out_state = states_indices[sma.state_timer_matrix[i]] + edges.append(f'{letter}{states_letters[out_state]}') + for input in sma.input_matrix[i]: + if input[0] == 0: + edges.append(f'{letter}{states_letters[states_indices[input[1]]]}') + dot.edges(edges) + if output_file is not None: + try: + dot.render(output_file, view=view) + except graphviz.exceptions.ExecutableNotFound: + log.info('Graphviz system executable not found, cannot render the graph') + return dot
+ + + def _instantiate_state_machine(self, *args, **kwargs): + return StateMachine(self.bpod) + +
+[docs] + def get_state_machine_trial(self, i): + # we define the trial number here for subclasses that may need it + sma = self._instantiate_state_machine(trial_number=i) + + if i == 0: # First trial exception start camera + session_delay_start = self.task_params.get('SESSION_DELAY_START', 0) + log.info('First trial initializing, will move to next trial only if:') + log.info('1. camera is detected') + log.info(f'2. {session_delay_start} sec have elapsed') + sma.add_state( + state_name='trial_start', + state_timer=0, + state_change_conditions={'Port1In': 'delay_initiation'}, + output_actions=[('SoftCode', SOFTCODE.TRIGGER_CAMERA), ('BNC1', 255)], + ) # start camera + sma.add_state( + state_name='delay_initiation', + state_timer=session_delay_start, + output_actions=[], + state_change_conditions={'Tup': 'reset_rotary_encoder'}, + ) + else: + sma.add_state( + state_name='trial_start', + state_timer=0, # ~100µs hardware irreducible delay + state_change_conditions={'Tup': 'reset_rotary_encoder'}, + output_actions=[self.bpod.actions.stop_sound, ('BNC1', 255)], + ) # stop all sounds + + # Reset the rotary encoder by sending the following opcodes via the modules serial interface + # - 'Z' (ASCII 90): Set current rotary encoder position to zero + # - 'E' (ASCII 69): Enable all position thresholds (that may have been disabled by a threshold-crossing) + # cf. https://sanworks.github.io/Bpod_Wiki/serial-interfaces/rotary-encoder-module-serial-interface/ + sma.add_state( + state_name='reset_rotary_encoder', + state_timer=0, + output_actions=[self.bpod.actions.rotary_encoder_reset], + state_change_conditions={'Tup': 'quiescent_period'}, + ) + + # Quiescent Period. If the wheel is moved past one of the thresholds: Reset the rotary encoder and start over. + # Continue with the stimulation once the quiescent period has passed without triggering movement thresholds. + sma.add_state( + state_name='quiescent_period', + state_timer=self.quiescent_period, + output_actions=[], + state_change_conditions={ + 'Tup': 'stim_on', + self.movement_left: 'reset_rotary_encoder', + self.movement_right: 'reset_rotary_encoder', + }, + ) + + # Show the visual stimulus. This is achieved by sending a time-stamped byte-message to Bonsai via the Rotary + # Encoder Module's ongoing USB-stream. Move to the next state once the Frame2TTL has been triggered, i.e., + # when the stimulus has been rendered on screen. Use the state-timer as a backup to prevent a stall. + sma.add_state( + state_name='stim_on', + state_timer=0.1, + output_actions=[self.bpod.actions.bonsai_show_stim], + state_change_conditions={'BNC1High': 'interactive_delay', 'BNC1Low': 'interactive_delay', 'Tup': 'interactive_delay'}, + ) + + # Defined delay between visual and auditory cue + sma.add_state( + state_name='interactive_delay', + state_timer=self.task_params.INTERACTIVE_DELAY, + output_actions=[], + state_change_conditions={'Tup': 'play_tone'}, + ) + + # Play tone. Move to next state if sound is detected. Use the state-timer as a backup to prevent a stall. + sma.add_state( + state_name='play_tone', + state_timer=0.1, + output_actions=[self.bpod.actions.play_tone], + state_change_conditions={'Tup': 'reset2_rotary_encoder', 'BNC2High': 'reset2_rotary_encoder'}, + ) + + # Reset rotary encoder (see above). Move on after brief delay (to avoid a race conditions in the bonsai flow). + sma.add_state( + state_name='reset2_rotary_encoder', + state_timer=0.05, + output_actions=[self.bpod.actions.rotary_encoder_reset], + state_change_conditions={'Tup': 'closed_loop'}, + ) + + # Start the closed loop state in which the animal controls the position of the visual stimulus by means of the + # rotary encoder. The three possible outcomes are: + # 1) wheel has NOT been moved past a threshold: continue with no-go condition + # 2) wheel has been moved in WRONG direction: continue with error condition + # 3) wheel has been moved in CORRECT direction: continue with reward condition + + sma.add_state( + state_name='closed_loop', + state_timer=self.task_params.RESPONSE_WINDOW, + output_actions=[self.bpod.actions.bonsai_closed_loop], + state_change_conditions={'Tup': 'no_go', self.event_error: 'freeze_error', self.event_reward: 'freeze_reward'}, + ) + + # No-go: hide the visual stimulus and play white noise. Go to exit_state after FEEDBACK_NOGO_DELAY_SECS. + sma.add_state( + state_name='no_go', + state_timer=self.task_params.FEEDBACK_NOGO_DELAY_SECS, + output_actions=[self.bpod.actions.bonsai_hide_stim, self.bpod.actions.play_noise], + state_change_conditions={'Tup': 'exit_state'}, + ) + + # Error: Freeze the stimulus and play white noise. + # Continue to hide_stim/exit_state once FEEDBACK_ERROR_DELAY_SECS have passed. + sma.add_state( + state_name='freeze_error', + state_timer=0, + output_actions=[self.bpod.actions.bonsai_freeze_stim], + state_change_conditions={'Tup': 'error'}, + ) + sma.add_state( + state_name='error', + state_timer=self.task_params.FEEDBACK_ERROR_DELAY_SECS, + output_actions=[self.bpod.actions.play_noise], + state_change_conditions={'Tup': 'hide_stim'}, + ) + + # Reward: open the valve for a defined duration (and set BNC1 to high), freeze stimulus in center of screen. + # Continue to hide_stim/exit_state once FEEDBACK_CORRECT_DELAY_SECS have passed. + sma.add_state( + state_name='freeze_reward', + state_timer=0, + output_actions=[self.bpod.actions.bonsai_show_center], + state_change_conditions={'Tup': 'reward'}, + ) + sma.add_state( + state_name='reward', + state_timer=self.reward_time, + output_actions=[('Valve1', 255), ('BNC1', 255)], + state_change_conditions={'Tup': 'correct'}, + ) + sma.add_state( + state_name='correct', + state_timer=self.task_params.FEEDBACK_CORRECT_DELAY_SECS - self.reward_time, + output_actions=[], + state_change_conditions={'Tup': 'hide_stim'}, + ) + + # Hide the visual stimulus. This is achieved by sending a time-stamped byte-message to Bonsai via the Rotary + # Encoder Module's ongoing USB-stream. Move to the next state once the Frame2TTL has been triggered, i.e., + # when the stimulus has been rendered on screen. Use the state-timer as a backup to prevent a stall. + sma.add_state( + state_name='hide_stim', + state_timer=0.1, + output_actions=[self.bpod.actions.bonsai_hide_stim], + state_change_conditions={'Tup': 'exit_state', 'BNC1High': 'exit_state', 'BNC1Low': 'exit_state'}, + ) + + # Wait for ITI_DELAY_SECS before ending the trial. Raise BNC1 to mark this event. + sma.add_state( + state_name='exit_state', + state_timer=self.task_params.ITI_DELAY_SECS, + output_actions=[('BNC1', 255)], + state_change_conditions={'Tup': 'exit'}, + ) + + return sma
+ + +
+[docs] + @abc.abstractmethod + def next_trial(self): + pass
+ + + @property + def default_reward_amount(self): + return self.task_params.REWARD_AMOUNT_UL + +
+[docs] + def draw_next_trial_info(self, pleft=0.5, **kwargs): + """Draw next trial variables. + + calls :meth:`send_trial_info_to_bonsai`. + This is called by the `next_trial` method before updating the Bpod state machine. + """ + assert len(self.task_params.STIM_POSITIONS) == 2, 'Only two positions are supported' + contrast = misc.draw_contrast(self.task_params.CONTRAST_SET, self.task_params.CONTRAST_SET_PROBABILITY_TYPE) + position = int(np.random.choice(self.task_params.STIM_POSITIONS, p=[pleft, 1 - pleft])) + quiescent_period = self.task_params.QUIESCENT_PERIOD + misc.truncated_exponential( + scale=0.35, min_value=0.2, max_value=0.5 + ) + stim_gain = ( + self.session_info.ADAPTIVE_GAIN_VALUE if self.task_params.get('ADAPTIVE_GAIN', False) else self.task_params.STIM_GAIN + ) + self.trials_table.at[self.trial_num, 'quiescent_period'] = quiescent_period + self.trials_table.at[self.trial_num, 'contrast'] = contrast + self.trials_table.at[self.trial_num, 'stim_phase'] = random.uniform(0, 2 * math.pi) + self.trials_table.at[self.trial_num, 'stim_sigma'] = self.task_params.STIM_SIGMA + self.trials_table.at[self.trial_num, 'stim_angle'] = self.task_params.STIM_ANGLE + self.trials_table.at[self.trial_num, 'stim_gain'] = stim_gain + self.trials_table.at[self.trial_num, 'stim_freq'] = self.task_params.STIM_FREQ + self.trials_table.at[self.trial_num, 'stim_reverse'] = self.task_params.STIM_REVERSE + self.trials_table.at[self.trial_num, 'trial_num'] = self.trial_num + self.trials_table.at[self.trial_num, 'position'] = position + self.trials_table.at[self.trial_num, 'reward_amount'] = self.default_reward_amount + self.trials_table.at[self.trial_num, 'stim_probability_left'] = pleft + + # use the kwargs dict to override computed values + for key, value in kwargs.items(): + if key == 'index': + pass + self.trials_table.at[self.trial_num, key] = value + + self.send_trial_info_to_bonsai()
+ + +
+[docs] + def trial_completed(self, bpod_data: dict[str, Any]) -> None: + # if the reward state has not been triggered, null the reward + if np.isnan(bpod_data['States timestamps']['reward'][0][0]): + self.trials_table.at[self.trial_num, 'reward_amount'] = 0 + self.trials_table.at[self.trial_num, 'reward_valve_time'] = self.reward_time + # update cumulative reward value + self.session_info.TOTAL_WATER_DELIVERED += self.trials_table.at[self.trial_num, 'reward_amount'] + self.session_info.NTRIALS += 1 + # SAVE TRIAL DATA + self.save_trial_data_to_json(bpod_data) + # this is a flag for the online plots. If online plots were in pyqt5, there is a file watcher functionality + Path(self.paths['DATA_FILE_PATH']).parent.joinpath('new_trial.flag').touch() + self.paths.SESSION_FOLDER.joinpath('transfer_me.flag').touch() + self.check_sync_pulses(bpod_data=bpod_data)
+ + +
+[docs] + def check_sync_pulses(self, bpod_data): + # todo move this in the post trial when we have a task flow + if not self.bpod.is_connected: + return + events = bpod_data['Events timestamps'] + if not misc.get_port_events(events, name='BNC1'): + log.warning("NO FRAME2TTL PULSES RECEIVED ON BPOD'S TTL INPUT 1") + if not misc.get_port_events(events, name='BNC2'): + log.warning("NO SOUND SYNC PULSES RECEIVED ON BPOD'S TTL INPUT 2") + if not misc.get_port_events(events, name='Port1'): + log.warning("NO CAMERA SYNC PULSES RECEIVED ON BPOD'S BEHAVIOR PORT 1")
+ + +
+[docs] + def show_trial_log(self, extra_info: dict[str, Any] | None = None, log_level: int = logging.INFO): + """ + Log the details of the current trial. + + This method retrieves information about the current trial from the + trials table and logs it. It can also incorporate additional information + provided through the `extra_info` parameter. + + Parameters + ---------- + extra_info : dict[str, Any], optional + A dictionary containing additional information to include in the + log. + + log_level : int, optional + The logging level to use when logging the trial information. + Default is logging.INFO. + + Notes + ----- + When overloading, make sure to call the super class and pass additional + log items by means of the extra_info parameter. See the implementation + of :py:meth:`~iblrig.base_choice_world.ActiveChoiceWorldSession.show_trial_log` in + :mod:`~iblrig.base_choice_world.ActiveChoiceWorldSession` for reference. + """ + # construct base info dict + trial_info = self.trials_table.iloc[self.trial_num] + info_dict = { + 'Stim. Position': trial_info.position, + 'Stim. Contrast': trial_info.contrast, + 'Stim. Phase': f'{trial_info.stim_phase:.2f}', + 'Stim. p Left': trial_info.stim_probability_left, + 'Water delivered': f'{self.session_info.TOTAL_WATER_DELIVERED:.1f} µl', + 'Time from Start': self.time_elapsed, + 'Temperature': f'{self.ambient_sensor_table.loc[self.trial_num, "Temperature_C"]:.1f} °C', + 'Air Pressure': f'{self.ambient_sensor_table.loc[self.trial_num, "AirPressure_mb"]:.1f} mb', + 'Rel. Humidity': f'{self.ambient_sensor_table.loc[self.trial_num, "RelativeHumidity"]:.1f} %', + } + + # update info dict with extra_info dict + if isinstance(extra_info, dict): + info_dict.update(extra_info) + + # log info dict + log.log(log_level, f'Outcome of Trial #{trial_info.trial_num}:') + max_key_length = max(len(key) for key in info_dict) + for key, value in info_dict.items(): + spaces = (max_key_length - len(key)) * ' ' + log.log(log_level, f'- {key}: {spaces}{str(value)}')
+ + + @property + def iti_reward(self): + """ + Returns the ITI time that needs to be set in order to achieve the desired ITI, + by subtracting the time it takes to give a reward from the desired ITI. + """ + return self.task_params.ITI_CORRECT - self.calibration.get('REWARD_VALVE_TIME', None) + + """ + Those are the properties that are used in the state machine code + """ + + @property + def reward_time(self): + return self.compute_reward_time(amount_ul=self.trials_table.at[self.trial_num, 'reward_amount']) + + @property + def quiescent_period(self): + return self.trials_table.at[self.trial_num, 'quiescent_period'] + + @property + def position(self): + return self.trials_table.at[self.trial_num, 'position'] + + @property + def event_error(self): + return self.device_rotary_encoder.THRESHOLD_EVENTS[(-1 if self.task_params.STIM_REVERSE else 1) * self.position] + + @property + def event_reward(self): + return self.device_rotary_encoder.THRESHOLD_EVENTS[(1 if self.task_params.STIM_REVERSE else -1) * self.position]
+ + + +
+[docs] +class HabituationChoiceWorldTrialData(ChoiceWorldTrialData): + """Pydantic Model for Trial Data, extended from :class:`~.iblrig.base_choice_world.ChoiceWorldTrialData`.""" + + delay_to_stim_center: NonNegativeFloat
+ + + +
+[docs] +class HabituationChoiceWorldSession(ChoiceWorldSession): + protocol_name = '_iblrig_tasks_habituationChoiceWorld' + TrialDataModel = HabituationChoiceWorldTrialData + +
+[docs] + def next_trial(self): + self.trial_num += 1 + self.draw_next_trial_info()
+ + +
+[docs] + def draw_next_trial_info(self, *args, **kwargs): + # update trial table fields specific to habituation choice world + self.trials_table.at[self.trial_num, 'delay_to_stim_center'] = np.random.normal(self.task_params.DELAY_TO_STIM_CENTER, 2) + super().draw_next_trial_info(*args, **kwargs)
+ + +
+[docs] + def get_state_machine_trial(self, i): + sma = StateMachine(self.bpod) + + if i == 0: # First trial exception start camera + log.info('Waiting for camera pulses...') + sma.add_state( + state_name='iti', + state_timer=3600, + state_change_conditions={'Port1In': 'stim_on'}, + output_actions=[self.bpod.actions.bonsai_hide_stim, ('SoftCode', SOFTCODE.TRIGGER_CAMERA), ('BNC1', 255)], + ) # start camera + else: + # NB: This state actually the inter-trial interval, i.e. the period of grey screen between stim off and stim on. + # During this period the Bpod TTL is HIGH and there are no stimuli. The onset of this state is trial end; + # the offset of this state is trial start! + sma.add_state( + state_name='iti', + state_timer=1, # Stim off for 1 sec + state_change_conditions={'Tup': 'stim_on'}, + output_actions=[self.bpod.actions.bonsai_hide_stim, ('BNC1', 255)], + ) + # This stim_on state is considered the actual trial start + sma.add_state( + state_name='stim_on', + state_timer=self.trials_table.at[self.trial_num, 'delay_to_stim_center'], + state_change_conditions={'Tup': 'stim_center'}, + output_actions=[self.bpod.actions.bonsai_show_stim, self.bpod.actions.play_tone], + ) + + sma.add_state( + state_name='stim_center', + state_timer=0.5, + state_change_conditions={'Tup': 'reward'}, + output_actions=[self.bpod.actions.bonsai_show_center], + ) + + sma.add_state( + state_name='reward', + state_timer=self.reward_time, # the length of time to leave reward valve open, i.e. reward size + state_change_conditions={'Tup': 'post_reward'}, + output_actions=[('Valve1', 255), ('BNC1', 255)], + ) + # This state defines the period after reward where Bpod TTL is LOW. + # NB: The stimulus is on throughout this period. The stim off trigger occurs upon exit. + # The stimulus thus remains in the screen centre for 0.5 + ITI_DELAY_SECS seconds. + sma.add_state( + state_name='post_reward', + state_timer=self.task_params.ITI_DELAY_SECS - self.reward_time, + state_change_conditions={'Tup': 'exit'}, + output_actions=[], + ) + return sma
+
+ + + +
+[docs] +class ActiveChoiceWorldTrialData(ChoiceWorldTrialData): + """Pydantic Model for Trial Data, extended from :class:`~.iblrig.base_choice_world.ChoiceWorldTrialData`.""" + + response_side: Annotated[int, Interval(ge=-1, le=1)] + response_time: NonNegativeFloat + trial_correct: bool
+ + + +
+[docs] +class ActiveChoiceWorldSession(ChoiceWorldSession): + """ + The ActiveChoiceWorldSession is a base class for protocols where the mouse is actively making decisions + by turning the wheel. It has the following characteristics + + - it is trial based + - it is decision based + - left and right simulus are equiprobable: there is no biased block + - a trial can either be correct / error / no_go depending on the side of the stimulus and the response + - it has a quantifiable performance by computing the proportion of correct trials of passive stimulations protocols or + habituation protocols. + + The TrainingChoiceWorld, BiasedChoiceWorld are all subclasses of this class + """ + + TrialDataModel = ActiveChoiceWorldTrialData + +
+[docs] + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.trials_table['stim_probability_left'] = np.zeros(NTRIALS_INIT, dtype=np.float64)
+ + + def _run(self): + # starts online plotting + if self.interactive: + subprocess.Popen( + ['view_session', str(self.paths['DATA_FILE_PATH']), str(self.paths['SETTINGS_FILE_PATH'])], + stdout=subprocess.DEVNULL, + stderr=subprocess.STDOUT, + ) + super()._run() + +
+[docs] + def show_trial_log(self, extra_info: dict[str, Any] | None = None, log_level: int = logging.INFO): + # construct info dict + trial_info = self.trials_table.iloc[self.trial_num] + info_dict = { + 'Response Time': f'{trial_info.response_time:.2f} s', + 'Trial Correct': trial_info.trial_correct, + 'N Trials Correct': self.session_info.NTRIALS_CORRECT, + 'N Trials Error': self.trial_num - self.session_info.NTRIALS_CORRECT, + } + + # update info dict with extra_info dict + if isinstance(extra_info, dict): + info_dict.update(extra_info) + + # call parent method + super().show_trial_log(extra_info=info_dict, log_level=log_level)
+ + +
+[docs] + def trial_completed(self, bpod_data): + """ + The purpose of this method is to + + - update the trials table with information about the behaviour coming from the bpod + Constraints on the state machine data: + - mandatory states: ['correct', 'error', 'no_go', 'reward'] + - optional states : ['omit_correct', 'omit_error', 'omit_no_go'] + + :param bpod_data: + :return: + """ + # get the response time from the behaviour data + response_time = bpod_data['States timestamps']['closed_loop'][0][1] - bpod_data['States timestamps']['stim_on'][0][0] + self.trials_table.at[self.trial_num, 'response_time'] = response_time + # get the trial outcome + state_names = ['correct', 'error', 'no_go', 'omit_correct', 'omit_error', 'omit_no_go'] + raw_outcome = {sn: ~np.isnan(bpod_data['States timestamps'].get(sn, [[np.NaN]])[0][0]) for sn in state_names} + try: + outcome = next(k for k in raw_outcome if raw_outcome[k]) + # Update response buffer -1 for left, 0 for nogo, and 1 for rightward + position = self.trials_table.at[self.trial_num, 'position'] + self.trials_table.at[self.trial_num, 'trial_correct'] = 'correct' in outcome + if 'correct' in outcome: + self.session_info.NTRIALS_CORRECT += 1 + self.trials_table.at[self.trial_num, 'response_side'] = -np.sign(position) + elif 'error' in outcome: + self.trials_table.at[self.trial_num, 'response_side'] = np.sign(position) + elif 'no_go' in outcome: + self.trials_table.at[self.trial_num, 'response_side'] = 0 + super().trial_completed(bpod_data) + # here we throw potential errors after having written the trial to disk + assert np.sum(list(raw_outcome.values())) == 1 + assert position != 0, 'the position value should be either 35 or -35' + except StopIteration as e: + log.error(f'No outcome detected for trial {self.trial_num}.') + log.error(f'raw_outcome: {raw_outcome}') + log.error('State names: ' + ', '.join(bpod_data['States timestamps'].keys())) + raise e + except AssertionError as e: + log.error(f'Assertion Error in trial {self.trial_num}.') + log.error(f'raw_outcome: {raw_outcome}') + log.error('State names: ' + ', '.join(bpod_data['States timestamps'].keys())) + raise e
+
+ + + +
+[docs] +class BiasedChoiceWorldTrialData(ActiveChoiceWorldTrialData): + """Pydantic Model for Trial Data, extended from :class:`~.iblrig.base_choice_world.ChoiceWorldTrialData`.""" + + block_num: NonNegativeInt = 0 + block_trial_num: NonNegativeInt = 0
+ + + +
+[docs] +class BiasedChoiceWorldSession(ActiveChoiceWorldSession): + """ + Biased choice world session is the instantiation of ActiveChoiceWorld where the notion of biased + blocks is introduced. + """ + + base_parameters_file = Path(__file__).parent.joinpath('base_biased_choice_world_params.yaml') + protocol_name = '_iblrig_tasks_biasedChoiceWorld' + TrialDataModel = BiasedChoiceWorldTrialData + +
+[docs] + def __init__(self, **kwargs): + super().__init__(**kwargs) + self.blocks_table = pd.DataFrame( + {'probability_left': np.zeros(NBLOCKS_INIT) * np.NaN, 'block_length': np.zeros(NBLOCKS_INIT, dtype=np.int16) * -1} + )
+ + +
+[docs] + def new_block(self): + """ + if block_init_5050 + First block has 50/50 probability of leftward stim + is 90 trials long + """ + self.block_num += 1 # the block number is zero based + self.block_trial_num = 0 + + # handles the block length logic + if self.task_params.BLOCK_INIT_5050 and self.block_num == 0: + block_len = 90 + else: + block_len = int( + misc.truncated_exponential( + scale=self.task_params.BLOCK_LEN_FACTOR, + min_value=self.task_params.BLOCK_LEN_MIN, + max_value=self.task_params.BLOCK_LEN_MAX, + ) + ) + if self.block_num == 0: + pleft = 0.5 if self.task_params.BLOCK_INIT_5050 else np.random.choice(self.task_params.BLOCK_PROBABILITY_SET) + elif self.block_num == 1 and self.task_params.BLOCK_INIT_5050: + pleft = np.random.choice(self.task_params.BLOCK_PROBABILITY_SET) + else: + # this switches the probability of leftward stim for the next block + pleft = round(abs(1 - self.blocks_table.loc[self.block_num - 1, 'probability_left']), 1) + self.blocks_table.at[self.block_num, 'block_length'] = block_len + self.blocks_table.at[self.block_num, 'probability_left'] = pleft
+ + +
+[docs] + def next_trial(self): + self.trial_num += 1 + # if necessary update the block number + self.block_trial_num += 1 + if self.block_num < 0 or self.block_trial_num > (self.blocks_table.loc[self.block_num, 'block_length'] - 1): + self.new_block() + # get and store probability left + pleft = self.blocks_table.loc[self.block_num, 'probability_left'] + # update trial table fields specific to biased choice world task + self.trials_table.at[self.trial_num, 'block_num'] = self.block_num + self.trials_table.at[self.trial_num, 'block_trial_num'] = self.block_trial_num + # save and send trial info to bonsai + self.draw_next_trial_info(pleft=pleft)
+ + +
+[docs] + def show_trial_log(self, extra_info: dict[str, Any] | None = None, log_level: int = logging.INFO): + # construct info dict + trial_info = self.trials_table.iloc[self.trial_num] + info_dict = { + 'Block Number': trial_info.block_num, + 'Block Length': self.blocks_table.loc[self.block_num, 'block_length'], + 'N Trials in Block': trial_info.block_trial_num, + } + + # update info dict with extra_info dict + if isinstance(extra_info, dict): + info_dict.update(extra_info) + + # call parent method + super().show_trial_log(extra_info=info_dict, log_level=log_level)
+
+ + + +
+[docs] +class TrainingChoiceWorldTrialData(ActiveChoiceWorldTrialData): + """Pydantic Model for Trial Data, extended from :class:`~.iblrig.base_choice_world.ActiveChoiceWorldTrialData`.""" + + training_phase: NonNegativeInt + debias_trial: bool + signed_contrast: float | None = None
+ + + +
+[docs] +class TrainingChoiceWorldSession(ActiveChoiceWorldSession): + """ + The TrainingChoiceWorldSession corresponds to the first training protocol of the choice world task. + This protocol has a complicated adaptation of the number of contrasts (embodied by the training_phase + property) and the reward amount, embodied by the adaptive_reward property. + """ + + protocol_name = '_iblrig_tasks_trainingChoiceWorld' + TrialDataModel = TrainingChoiceWorldTrialData + +
+[docs] + def __init__(self, training_phase=-1, adaptive_reward=-1.0, adaptive_gain=None, **kwargs): + super().__init__(**kwargs) + inferred_training_phase, inferred_adaptive_reward, inferred_adaptive_gain = self.get_subject_training_info() + if training_phase == -1: + log.critical(f'Got training phase: {inferred_training_phase}') + self.training_phase = inferred_training_phase + else: + log.critical(f'Training phase manually set to: {training_phase}') + self.training_phase = training_phase + if adaptive_reward == -1: + log.critical(f'Got Adaptive reward {inferred_adaptive_reward} uL') + self.session_info['ADAPTIVE_REWARD_AMOUNT_UL'] = inferred_adaptive_reward + else: + log.critical(f'Adaptive reward manually set to {adaptive_reward} uL') + self.session_info['ADAPTIVE_REWARD_AMOUNT_UL'] = adaptive_reward + if adaptive_gain is None: + log.critical(f'Got Adaptive gain {inferred_adaptive_gain} degrees/mm') + self.session_info['ADAPTIVE_GAIN_VALUE'] = inferred_adaptive_gain + else: + log.critical(f'Adaptive gain manually set to {adaptive_gain} degrees/mm') + self.session_info['ADAPTIVE_GAIN_VALUE'] = adaptive_gain + self.var = {'training_phase_trial_counts': np.zeros(6), 'last_10_responses_sides': np.zeros(10)}
+ + + @property + def default_reward_amount(self): + return self.session_info.get('ADAPTIVE_REWARD_AMOUNT_UL', self.task_params.REWARD_AMOUNT_UL) + +
+[docs] + def get_subject_training_info(self): + """ + Get the previous session's according to this session parameters and deduce the + training level, adaptive reward amount and adaptive gain value. + + Returns + ------- + training_info: dict + Dictionary with keys: training_phase, adaptive_reward, adaptive_gain + """ + training_info, _ = choiceworld.get_subject_training_info( + subject_name=self.session_info.SUBJECT_NAME, + task_name=self.protocol_name, + stim_gain=self.task_params.AG_INIT_VALUE, + stim_gain_on_error=self.task_params.STIM_GAIN, + default_reward=self.task_params.REWARD_AMOUNT_UL, + local_path=self.iblrig_settings['iblrig_local_data_path'], + remote_path=self.iblrig_settings['iblrig_remote_data_path'], + lab=self.iblrig_settings['ALYX_LAB'], + iblrig_settings=self.iblrig_settings, + ) + return training_info['training_phase'], training_info['adaptive_reward'], training_info['adaptive_gain']
+ + +
+[docs] + def compute_performance(self): + """Aggregate the trials table to compute the performance of the mouse on each contrast.""" + self.trials_table['signed_contrast'] = self.trials_table.contrast * self.trials_table.position + performance = self.trials_table.groupby(['signed_contrast']).agg( + last_50_perf=pd.NamedAgg(column='trial_correct', aggfunc=lambda x: np.sum(x[np.maximum(-50, -x.size) :]) / 50), + ntrials=pd.NamedAgg(column='trial_correct', aggfunc='count'), + ) + return performance
+ + +
+[docs] + def check_training_phase(self): + """Check if the mouse is ready to move to the next training phase.""" + move_on = False + if self.training_phase == 0: # each of the -1, -.5, .5, 1 contrast should be above 80% perf to switch + performance = self.compute_performance() + passing = performance[np.abs(performance.index) >= 0.5]['last_50_perf'] + if np.all(passing > 0.8) and passing.size == 4: + move_on = True + elif self.training_phase == 1: # each of the -.25, .25 should be above 80% perf to switch + performance = self.compute_performance() + passing = performance[np.abs(performance.index) == 0.25]['last_50_perf'] + if np.all(passing > 0.8) and passing.size == 2: + move_on = True + elif 5 > self.training_phase >= 2: # for the next phases, always switch after 200 trials + if self.var['training_phase_trial_counts'][self.training_phase] >= 200: + move_on = True + if move_on: + self.training_phase = np.minimum(5, self.training_phase + 1) + log.warning(f'Moving on to training phase {self.training_phase}, {self.trial_num}')
+ + +
+[docs] + def next_trial(self): + # update counters + self.trial_num += 1 + self.var['training_phase_trial_counts'][self.training_phase] += 1 + # check if the subject graduates to a new training phase + self.check_training_phase() + # draw the next trial + signed_contrast = choiceworld.draw_training_contrast(self.training_phase) + position = self.task_params.STIM_POSITIONS[int(np.sign(signed_contrast) == 1)] + contrast = np.abs(signed_contrast) + # debiasing: if the previous trial was incorrect and easy repeat the trial + if self.task_params.DEBIAS and self.trial_num >= 1 and self.training_phase < 5: + last_contrast = self.trials_table.loc[self.trial_num - 1, 'contrast'] + do_debias_trial = (self.trials_table.loc[self.trial_num - 1, 'trial_correct'] != 1) and last_contrast >= 0.5 + self.trials_table.at[self.trial_num, 'debias_trial'] = do_debias_trial + if do_debias_trial: + iresponse = self.trials_table['response_side'] != 0 # trials that had a response + # takes the average of right responses over last 10 response trials + average_right = np.mean(self.trials_table['response_side'][iresponse[-np.maximum(10, iresponse.size) :]] == 1) + # the next probability of next stimulus being on the left is a draw from a normal distribution + # centered on average right with sigma 0.5. If it is less than 0.5 the next stimulus will be on the left + position = self.task_params.STIM_POSITIONS[int(np.random.normal(average_right, 0.5) >= 0.5)] + # contrast is the last contrast + contrast = last_contrast + else: + self.trials_table.at[self.trial_num, 'debias_trial'] = False + # save and send trial info to bonsai + self.draw_next_trial_info(pleft=self.task_params.PROBABILITY_LEFT, position=position, contrast=contrast) + self.trials_table.at[self.trial_num, 'training_phase'] = self.training_phase
+ + +
+[docs] + def show_trial_log(self, extra_info: dict[str, Any] | None = None, log_level: int = logging.INFO): + # construct info dict + info_dict = { + 'Contrast Set': np.unique(np.abs(choiceworld.contrasts_set(self.training_phase))), + 'Training Phase': self.training_phase, + } + + # update info dict with extra_info dict + if isinstance(extra_info, dict): + info_dict.update(extra_info) + + # call parent method + super().show_trial_log(extra_info=info_dict, log_level=log_level)
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/base_tasks.html b/_modules/iblrig/base_tasks.html new file mode 100644 index 000000000..eff28b243 --- /dev/null +++ b/_modules/iblrig/base_tasks.html @@ -0,0 +1,1806 @@ + + + + + + iblrig.base_tasks — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.base_tasks

+"""
+Commonalities for all tasks.
+
+This module provides hardware mixins that can be used together with BaseSession to compose tasks.
+This module tries to exclude task related logic.
+"""
+
+import argparse
+import contextlib
+import datetime
+import importlib.metadata
+import inspect
+import json
+import logging
+import signal
+import sys
+import time
+import traceback
+from abc import ABC, abstractmethod
+from collections import OrderedDict
+from collections.abc import Callable
+from pathlib import Path
+from typing import Protocol, final
+
+import numpy as np
+import pandas as pd
+import serial
+import yaml
+from pythonosc import udp_client
+
+import ibllib.io.session_params as ses_params
+import iblrig.graphic as graph
+import iblrig.path_helper
+import pybpodapi
+from ibllib.oneibl.registration import IBLRegistrationClient
+from iblrig import net, path_helper, sound
+from iblrig.constants import BASE_PATH, BONSAI_EXE, PYSPIN_AVAILABLE
+from iblrig.frame2ttl import Frame2TTL
+from iblrig.hardware import SOFTCODE, Bpod, MyRotaryEncoder, sound_device_factory
+from iblrig.hifi import HiFi
+from iblrig.path_helper import load_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings, TrialDataModel
+from iblrig.tools import call_bonsai
+from iblrig.transfer_experiments import BehaviorCopier, VideoCopier
+from iblrig.valve import Valve
+from iblutil.io.net.base import ExpMessage
+from iblutil.spacer import Spacer
+from iblutil.util import Bunch, flatten, setup_logger
+from one.alf.io import next_num_folder
+from one.api import ONE, OneAlyx
+from pybpodapi.protocol import StateMachine
+
+OSC_CLIENT_IP = '127.0.0.1'
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class HasBpod(Protocol): + bpod: Bpod
+ + + +
+[docs] +class BaseSession(ABC): + version = None + """str: !!CURRENTLY UNUSED!! task version string.""" + # protocol_name: str | None = None + """str: The name of the task protocol (NB: avoid spaces).""" + base_parameters_file: Path | None = None + """Path: A YAML file containing base, default task parameters.""" + is_mock = False + """list of str: One or more ibllib.pipes.tasks.Task names for task extraction.""" + logger: logging.Logger = None + """logging.Logger: Log instance used solely to keep track of log level passed to constructor.""" + experiment_description: dict = {} + """dict: The experiment description.""" + extractor_tasks: list | None = None + """list of str: An optional list of pipeline task class names to instantiate when preprocessing task data.""" + + TrialDataModel: type[TrialDataModel] + + @property + @abstractmethod + def protocol_name(self) -> str: ... + +
+[docs] + def __init__( + self, + subject=None, + task_parameter_file=None, + file_hardware_settings=None, + hardware_settings: HardwareSettings = None, + file_iblrig_settings=None, + iblrig_settings: RigSettings = None, + one=None, + interactive=True, + projects=None, + procedures=None, + stub=None, + subject_weight_grams=None, + append=False, + wizard=False, + log_level='INFO', + **kwargs, + ): + """ + :param subject: The subject nickname. Required. + :param task_parameter_file: an optional path to the task_parameters.yaml file + :param file_hardware_settings: name of the hardware file in the settings folder, or full file path + :param hardware_settings: an optional dictionary of hardware settings. Keys will override any keys in the file + :param file_iblrig_settings: name of the iblrig file in the settings folder, or full file path + :param iblrig_settings: an optional dictionary of iblrig settings. Keys will override any keys in the file + :param one: an optional instance of ONE + :param interactive: + :param projects: An optional list of Alyx protocols. + :param procedures: An optional list of Alyx procedures. + :param subject_weight_grams: weight of the subject + :param stub: A full path to an experiment description file containing experiment information. + :param append: bool, if True, append to the latest existing session of the same subject for the same day + """ + self.extractor_tasks = getattr(self, 'extractor_tasks', None) + self._logger = None + self._setup_loggers(level=log_level) + if not isinstance(self, EmptySession): + log.info(f'Running iblrig {iblrig.__version__}, pybpod version {pybpodapi.__version__}') + log.info(f'Session call: {" ".join(sys.argv)}') + self.interactive = interactive + self._one = one + self.init_datetime = datetime.datetime.now() + + # loads in the settings: first load the files, then update with the input argument if provided + self.hardware_settings: HardwareSettings = load_pydantic_yaml(HardwareSettings, file_hardware_settings) + if hardware_settings is not None: + self.hardware_settings.update(hardware_settings) + HardwareSettings.model_validate(self.hardware_settings) + self.iblrig_settings: RigSettings = load_pydantic_yaml(RigSettings, file_iblrig_settings) + if iblrig_settings is not None: + self.iblrig_settings.update(iblrig_settings) + RigSettings.model_validate(self.iblrig_settings) + + self.wizard = wizard + + # Load the tasks settings, from the task folder or override with the input argument + self.task_params = self.read_task_parameter_files(task_parameter_file) + + self.session_info = Bunch( + { + 'NTRIALS': 0, + 'NTRIALS_CORRECT': 0, + 'PROCEDURES': procedures, + 'PROJECTS': projects, + 'SESSION_START_TIME': self.init_datetime.isoformat(), + 'SESSION_END_TIME': None, + 'SESSION_NUMBER': 0, + 'SUBJECT_NAME': subject, + 'SUBJECT_WEIGHT': subject_weight_grams, + 'TOTAL_WATER_DELIVERED': 0, + } + ) + # Executes mixins init methods + self._execute_mixins_shared_function('init_mixin') + self.paths = self._init_paths(append=append) + if not isinstance(self, EmptySession): + log.info(f'Session raw data: {self.paths.SESSION_RAW_DATA_FOLDER}') + # Prepare the experiment description dictionary + self.experiment_description = self.make_experiment_description_dict( + self.protocol_name, + self.paths.get('TASK_COLLECTION'), + procedures, + projects, + self.hardware_settings, + stub, + extractors=self.extractor_tasks, + )
+ + +
+[docs] + @classmethod + def get_task_file(cls) -> Path: + """ + Get the path to the task's python file. + + Returns + ------- + Path + The path to the task file. + """ + return Path(inspect.getfile(cls))
+ + +
+[docs] + @classmethod + def get_task_directory(cls) -> Path: + """ + Get the path to the task's directory. + + Returns + ------- + Path + The path to the task's directory. + """ + return cls.get_task_file().parent
+ + +
+[docs] + @classmethod + def read_task_parameter_files(cls, task_parameter_file: str | Path | None = None) -> Bunch: + """ + Get the task's parameters from the various YAML files in the hierarchy. + + Parameters + ---------- + task_parameter_file : str or Path, optional + Path to override the task parameter file + + Returns + ------- + Bunch + Task parameters + """ + # Load the tasks settings, from the task folder or override with the input argument + base_parameters_files = [task_parameter_file or cls.get_task_directory().joinpath('task_parameters.yaml')] + + # loop through the task hierarchy to gather parameter files + for c in cls.__mro__: + base_file = getattr(c, 'base_parameters_file', None) + if base_file is not None: + base_parameters_files.append(base_file) + + # remove list duplicates while preserving order, we want the highest order first + base_parameters_files = list(reversed(list(dict.fromkeys(base_parameters_files)))) + + # loop through files and update the dictionary, the latest files in the hierarchy have precedence + task_params = dict() + for param_file in base_parameters_files: + if Path(param_file).exists(): + with open(param_file) as fp: + params = yaml.safe_load(fp) + if params is not None: + task_params.update(params) + + # at last sort the dictionary so itś easier for a human to navigate the many keys, return as a Bunch + return Bunch(sorted(task_params.items()))
+ + + def _init_paths(self, append: bool = False) -> Bunch: + r""" + Initialize session paths. + + Parameters + ---------- + append : bool + Iterate task collection within today's most recent session folder for the selected subject, instead of + iterating session number. + + Returns + ------- + Bunch + Bunch with keys: + + * BONSAI: full path to the bonsai executable + `C:\iblrigv8\Bonsai\Bonsai.exe` + * VISUAL_STIM_FOLDER: full path to the visual stimulus folder + `C:\iblrigv8\visual_stim` + * LOCAL_SUBJECT_FOLDER: full path to the local subject folder + `C:\iblrigv8_data\mainenlab\Subjects` + * REMOTE_SUBJECT_FOLDER: full path to the remote subject folder + `Y:\Subjects` + * SESSION_FOLDER: full path to the current session: + `C:\iblrigv8_data\mainenlab\Subjects\SWC_043\2019-01-01\001` + * TASK_COLLECTION: folder name of the current task + `raw_task_data_00` + * SESSION_RAW_DATA_FOLDER: concatenation of the session folder and the task collection. + This is where the task data gets written + `C:\iblrigv8_data\mainenlab\Subjects\SWC_043\2019-01-01\001\raw_task_data_00` + * DATA_FILE_PATH: contains the bpod trials + `C:\iblrigv8_data\mainenlab\Subjects\SWC_043\2019-01-01\001\raw_task_data_00\_iblrig_taskData.raw.jsonable` + * SETTINGS_FILE_PATH: contains the task settings + `C:\iblrigv8_data\mainenlab\Subjects\SWC_043\2019-01-01\001\raw_task_data_00\_iblrig_taskSettings.raw.json` + """ + rig_computer_paths = path_helper.get_local_and_remote_paths( + local_path=self.iblrig_settings.iblrig_local_data_path, + remote_path=self.iblrig_settings.iblrig_remote_data_path, + lab=self.iblrig_settings.ALYX_LAB, + iblrig_settings=self.iblrig_settings, + ) + paths = Bunch({'IBLRIG_FOLDER': BASE_PATH}) + paths.BONSAI = BONSAI_EXE + paths.VISUAL_STIM_FOLDER = BASE_PATH.joinpath('visual_stim') + paths.LOCAL_SUBJECT_FOLDER = rig_computer_paths['local_subjects_folder'] + paths.REMOTE_SUBJECT_FOLDER = rig_computer_paths['remote_subjects_folder'] + # initialize the session path + date_folder = paths.LOCAL_SUBJECT_FOLDER.joinpath( + self.session_info.SUBJECT_NAME, self.session_info.SESSION_START_TIME[:10] + ) + if append: + # this is the case where we append a new protocol to an existing session + todays_sessions = sorted(filter(Path.is_dir, date_folder.glob('*')), reverse=True) + assert len(todays_sessions) > 0, f'Trying to chain a protocol, but no session folder found in {date_folder}' + paths.SESSION_FOLDER = todays_sessions[0] + paths.TASK_COLLECTION = iblrig.path_helper.iterate_collection(paths.SESSION_FOLDER) + if self.hardware_settings.get('MAIN_SYNC', False) and not paths.TASK_COLLECTION.endswith('00'): + """ + Chained protocols make little sense when Bpod is the main sync as there is no + continuous acquisition between protocols. Only one sync collection can be defined in + the experiment description file. + If you are running experiments with an ephys rig (nidq) or an external daq, you should + correct the MAIN_SYNC parameter in the hardware settings file in ./settings/hardware_settings.yaml + """ + raise RuntimeError('Chained protocols not supported for bpod-only sessions') + else: + # in this case the session path is created from scratch + paths.SESSION_FOLDER = date_folder / next_num_folder(date_folder) + paths.TASK_COLLECTION = iblrig.path_helper.iterate_collection(paths.SESSION_FOLDER) + + self.session_info.SESSION_NUMBER = int(paths.SESSION_FOLDER.name) + paths.SESSION_RAW_DATA_FOLDER = paths.SESSION_FOLDER.joinpath(paths.TASK_COLLECTION) + paths.DATA_FILE_PATH = paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_taskData.raw.jsonable') + paths.SETTINGS_FILE_PATH = paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_taskSettings.raw.json') + return paths + + @property + def exp_ref(self): + """Construct an experiment reference string from the session info attribute.""" + subject, date, number = (self.session_info[k] for k in ('SUBJECT_NAME', 'SESSION_START_TIME', 'SESSION_NUMBER')) + if not all([subject, date, number]): + return None + return self.one.dict2ref(dict(subject=subject, date=date[:10], sequence=str(number))) + + def _setup_loggers(self, level='INFO', level_bpod='WARNING', file=None): + self._logger = setup_logger('iblrig', level=level, file=file) # logger attr used by create_session to determine log level + setup_logger('pybpodapi', level=level_bpod, file=file) + + @staticmethod + def _remove_file_loggers(): + for logger_name in ['iblrig', 'pybpodapi']: + logger = logging.getLogger(logger_name) + file_handlers = [fh for fh in logger.handlers if isinstance(fh, logging.FileHandler)] + for fh in file_handlers: + fh.close() + logger.removeHandler(fh) + +
+[docs] + @staticmethod + def make_experiment_description_dict( + task_protocol: str, + task_collection: str, + procedures: list = None, + projects: list = None, + hardware_settings: dict | HardwareSettings = None, + stub: Path = None, + extractors: list = None, + camera_config: str = None, + ): + """ + Construct an experiment description dictionary. + + Parameters + ---------- + task_protocol : str + The task protocol name, e.g. _ibl_trainingChoiceWorld2.0.0. + task_collection : str + The task collection name, e.g. raw_task_data_00. + procedures : list + An optional list of Alyx procedures. + projects : list + An optional list of Alyx protocols. + hardware_settings : dict + An optional dict of hardware devices, loaded from the hardware_settings.yaml file. + stub : dict + An optional experiment description stub to update. + extractors: list + An optional list of extractor names for the task. + camera_config : str + The camera configuration name in the hardware settings. Defaults to the first key in + 'device_cameras'. + + Returns + ------- + dict + The experiment description. + """ + description = ses_params.read_params(stub) if stub else {} + + # Add hardware devices + if hardware_settings is not None: + if isinstance(hardware_settings, HardwareSettings): + hardware_settings = hardware_settings.model_dump() + devices = {} + cams = hardware_settings.get('device_cameras', None) + if cams: + devices['cameras'] = {} + camera_config = camera_config or next((k for k in cams), {}) + devices.update(VideoCopier.config2stub(cams[camera_config])['devices']) + if hardware_settings.get('device_microphone', None): + devices['microphone'] = {'microphone': {'collection': task_collection, 'sync_label': 'audio'}} + ses_params.merge_params(description, {'devices': devices}) + + # Add projects and procedures + description['procedures'] = list(set(description.get('procedures', []) + (procedures or []))) + description['projects'] = list(set(description.get('projects', []) + (projects or []))) + is_main_sync = (hardware_settings or {}).get('MAIN_SYNC', False) + # Add sync key if required + if is_main_sync and 'sync' not in description: + description['sync'] = { + 'bpod': {'collection': task_collection, 'acquisition_software': 'pybpod', 'extension': '.jsonable'} + } + # Add task + task = {task_protocol: {'collection': task_collection}} + if not is_main_sync: + task[task_protocol]['sync_label'] = 'bpod' + if extractors: + assert isinstance(extractors, list), 'extractors parameter must be a list of strings' + task[task_protocol].update({'extractors': extractors}) + if 'tasks' not in description: + description['tasks'] = [task] + else: + description['tasks'].append(task) + return description
+ + + def _make_task_parameters_dict(self): + """ + Create dictionary that will be saved to the settings json file for extraction. + + Returns + ------- + dict + A dictionary that will be saved to the settings json file for extraction. + """ + output_dict = dict(self.task_params) # Grab parameters from task_params session + output_dict.update(self.hardware_settings.model_dump()) # Update dict with hardware settings from session + output_dict.update(dict(self.session_info)) # Update dict with session_info (subject, procedure, projects) + patch_dict = { # Various values added to ease transition from iblrig v7 to v8, different home may be desired + 'IBLRIG_VERSION': iblrig.__version__, + 'PYBPOD_PROTOCOL': self.protocol_name, + 'ALYX_USER': self.iblrig_settings.ALYX_USER, + 'ALYX_LAB': self.iblrig_settings.ALYX_LAB, + } + with contextlib.suppress(importlib.metadata.PackageNotFoundError): + patch_dict['PROJECT_EXTRACTION_VERSION'] = importlib.metadata.version('project_extraction') + output_dict.update(patch_dict) + return output_dict + +
+[docs] + def save_task_parameters_to_json_file(self, destination_folder: Path | None = None) -> Path: + """ + Collects the various settings and parameters of the session and outputs them to a JSON file. + + Returns + ------- + Path + Path to the resultant JSON file + """ + output_dict = self._make_task_parameters_dict() + if destination_folder: + json_file = destination_folder.joinpath('_iblrig_taskSettings.raw.json') + else: + json_file = self.paths['SETTINGS_FILE_PATH'] + json_file.parent.mkdir(parents=True, exist_ok=True) + with open(json_file, 'w') as outfile: + json.dump(output_dict, outfile, indent=4, sort_keys=True, default=str) # converts datetime objects to string + return json_file # PosixPath
+ + +
+[docs] + @final + def save_trial_data_to_json(self, bpod_data: dict): + """Validate and save trial data. + + This method retrieve's the current trial's data from the trial_table and validates it using a Pydantic model + (self.TrialDataDefinition). In merges in the trial's bpod_data dict and appends everything to the session's + JSON data file. + + Parameters + ---------- + bpod_data : dict + Trial data returned from pybpod. + """ + # get trial's data as a dict + trial_data = self.trials_table.iloc[self.trial_num].to_dict() + + # warn about entries not covered by pydantic model + if trial_data.get('trial_num', 1) == 0: + for key in set(trial_data.keys()) - set(self.TrialDataModel.model_fields) - {'index'}: + log.warning( + f'Key "{key}" in trial_data is missing from TrialDataModel - ' + f'its value ({trial_data[key]}) will not be validated.' + ) + + # validate by passing through pydantic model + trial_data = self.TrialDataModel.model_validate(trial_data).model_dump() + + # add bpod_data as 'behavior_data' + trial_data['behavior_data'] = bpod_data + + # write json data to file + with open(self.paths['DATA_FILE_PATH'], 'a') as fp: + fp.write(json.dumps(trial_data) + '\n')
+ + + @property + def one(self): + """ONE getter.""" + if self._one is None: + if self.iblrig_settings['ALYX_URL'] is None: + return + info_str = ( + f"alyx client with user name {self.iblrig_settings['ALYX_USER']} " + + f"and url: {self.iblrig_settings['ALYX_URL']}" + ) + try: + self._one = ONE( + base_url=str(self.iblrig_settings['ALYX_URL']), + username=self.iblrig_settings['ALYX_USER'], + mode='remote', + cache_rest=None, + ) + log.info('instantiated ' + info_str) + except Exception: + log.error(traceback.format_exc()) + log.error('could not connect to ' + info_str) + return self._one + +
+[docs] + def register_to_alyx(self): + """ + Registers the session to Alyx. + + This registers the session using the IBLRegistrationClient class. This uses the settings + file(s) and experiment description file to extract the session data. This may be called + any number of times and if the session record already exists in Alyx it will be updated. + If session registration fails, it will be done before extraction in the ibllib pipeline. + + Note that currently the subject weight is registered once and only once. The recorded + weight of the first protocol run is used. + + Water administrations are added separately by this method: it is expected that + `register_session` is first called with no recorded total water. This method will then add + a water administration each time it is called, and should therefore be called only once + after each protocol is run. If water administration registration fails for all protocols, + this will be done before extraction in the ibllib pipline, however, if a water + administration is successfully registered for one protocol and subsequent ones fail to + register, these will not be added before extraction in ibllib and therefore must be + manually added to Alyx. + + Returns + ------- + dict + The registered session record. + + See Also + -------- + :external+iblenv:meth:`ibllib.oneibl.registration.IBLRegistrationClient.register_session` - The registration method. + """ + if self.session_info['SUBJECT_NAME'] in ('iblrig_test_subject', 'test', 'test_subject'): + log.warning('Not registering test subject to Alyx') + return + if not self.one or self.one.offline: + return + try: + client = IBLRegistrationClient(self.one) + ses, _ = client.register_session(self.paths.SESSION_FOLDER, register_reward=False) + except Exception: + log.error(traceback.format_exc()) + log.error('Could not register session to Alyx') + return + # add the water administration if there was water administered + try: + if self.session_info['TOTAL_WATER_DELIVERED']: + wa = client.register_water_administration( + self.session_info.SUBJECT_NAME, + self.session_info['TOTAL_WATER_DELIVERED'] / 1000, + session=ses['url'][-36:], + water_type=self.task_params.get('REWARD_TYPE', None), + ) + log.info(f"Water administered registered in Alyx database: {ses['subject']}, " f"{wa['water_administered']}mL") + except Exception: + log.error(traceback.format_exc()) + log.error('Could not register water administration to Alyx') + return + return ses
+ + + def _execute_mixins_shared_function(self, pattern): + """ + Loop over all methods of the class that start with pattern and execute them. + + Parameters + ---------- + pattern : str + 'init_mixin', 'start_mixin', 'stop_mixin', or 'cleanup_mixin' + """ + method_names = [method for method in dir(self) if method.startswith(pattern)] + methods = [getattr(self, method) for method in method_names if inspect.ismethod(getattr(self, method))] + for meth in methods: + meth() + + @property + def time_elapsed(self): + return datetime.datetime.now() - self.init_datetime + +
+[docs] + def mock(self): + self.is_mock = True
+ + +
+[docs] + def create_session(self): + """ + Create the session path and save json parameters in the task collection folder. + + This will also create the protocol folder. + """ + self.paths['TASK_PARAMETERS_FILE'] = self.save_task_parameters_to_json_file() + # enable file logging + logfile = self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_ibl_log.info-acquisition.log') + self._setup_loggers(level=self._logger.level, file=logfile) + # copy the acquisition stub to the remote session folder + sc = BehaviorCopier(self.paths.SESSION_FOLDER, remote_subjects_folder=self.paths['REMOTE_SUBJECT_FOLDER']) + sc.initialize_experiment(self.experiment_description, overwrite=False) + self.register_to_alyx()
+ + +
+[docs] + def run(self): + """ + Common pre-run instructions for all tasks. + + Defines sigint handler for a graceful exit. + """ + # here we make sure we connect to the hardware before writing the session to disk + # this prevents from incrementing endlessly the session number if the hardware fails to connect + self.start_hardware() + self.create_session() + # When not running the first chained protocol, we can skip the weighing dialog + first_protocol = int(self.paths.SESSION_RAW_DATA_FOLDER.name.split('_')[-1]) == 0 + if self.session_info.SUBJECT_WEIGHT is None and self.interactive and first_protocol: + self.session_info.SUBJECT_WEIGHT = graph.numinput( + 'Subject weighing (gr)', f'{self.session_info.SUBJECT_NAME} weight (gr):', nullable=False + ) + + def sigint_handler(*args, **kwargs): + # create a signal handler for a graceful exit: create a stop flag in the session folder + self.paths.SESSION_FOLDER.joinpath('.stop').touch() + log.critical('SIGINT signal detected, will exit at the end of the trial') + + # if upon starting there is a flag just remove it, this is to prevent killing a session in the egg + if self.paths.SESSION_FOLDER.joinpath('.stop').exists(): + self.paths.SESSION_FOLDER.joinpath('.stop').unlink() + + signal.signal(signal.SIGINT, sigint_handler) + self._run() # runs the specific task logic i.e. trial loop etc... + # post task instructions + log.critical('Graceful exit') + log.info(f'Session {self.paths.SESSION_RAW_DATA_FOLDER}') + self.session_info.SESSION_END_TIME = datetime.datetime.now().isoformat() + if self.interactive and not self.wizard: + self.session_info.POOP_COUNT = graph.numinput( + 'Poop count', f'{self.session_info.SUBJECT_NAME} droppings count:', nullable=True, askint=True + ) + self.save_task_parameters_to_json_file() + self.register_to_alyx() + self._execute_mixins_shared_function('stop_mixin') + self._execute_mixins_shared_function('cleanup_mixin')
+ + +
+[docs] + @abstractmethod + def start_hardware(self): + """ + Start the hardware. + + This method doesn't explicitly start the mixins as the order has to be defined in the child classes. + This needs to be implemented in the child classes, and should start and connect to all hardware pieces. + """ + ...
+ + + @abstractmethod + def _run(self): ... + +
+[docs] + @staticmethod + def extra_parser(): + """ + Specify extra kwargs arguments to expose to the user prior running the task. + + Make sure you instantiate the parser. + + Returns + ------- + argparse.ArgumentParser + The extra parser instance. + """ + parser = argparse.ArgumentParser(add_help=False) + return parser
+
+ + + +# this class gets called to get the path constructor utility to predict the session path +
+[docs] +class EmptySession(BaseSession): + protocol_name = 'empty' + + def _run(self): + pass + +
+[docs] + def start_hardware(self): + pass
+
+ + + +
+[docs] +class OSCClient(udp_client.SimpleUDPClient): + """ + Handles communication to Bonsai using a UDP Client + OSC channels: + USED: + /t -> (int) trial number current + /p -> (int) position of stimulus init for current trial + /h -> (float) phase of gabor for current trial + /c -> (float) contrast of stimulus for current trial + /f -> (float) frequency of gabor patch for current trial + /a -> (float) angle of gabor patch for current trial + /g -> (float) gain of RE to visual stim displacement + /s -> (float) sigma of the 2D gaussian of gabor + /e -> (int) events transitions USED BY SOFTCODE HANDLER FUNC + /r -> (int) whether to reverse the side contingencies (0, 1) + """ + + OSC_PROTOCOL = { + 'trial_num': dict(mess='/t', type=int), + 'position': dict(mess='/p', type=int), + 'stim_phase': dict(mess='/h', type=float), + 'contrast': dict(mess='/c', type=float), + 'stim_freq': dict(mess='/f', type=float), + 'stim_angle': dict(mess='/a', type=float), + 'stim_gain': dict(mess='/g', type=float), + 'stim_sigma': dict(mess='/s', type=float), + # 'stim_reverse': dict(mess='/r', type=int), # this is not handled by Bonsai + } + +
+[docs] + def __init__(self, port, ip='127.0.0.1'): + super().__init__(ip, port)
+ + + def __del__(self): + self._sock.close() + +
+[docs] + def send2bonsai(self, **kwargs): + """ + :param see list of keys in OSC_PROTOCOL + :example: client.send2bonsai(trial_num=6, sim_freq=50) + :return: + """ + for k in kwargs: + if k in self.OSC_PROTOCOL: + # need to convert basic numpy types to low-level python types for + # punch card generation OSC module, I might as well have written C code + value = kwargs[k].item() if isinstance(kwargs[k], np.generic) else kwargs[k] + self.send_message(self.OSC_PROTOCOL[k]['mess'], self.OSC_PROTOCOL[k]['type'](value))
+ + +
+[docs] + def exit(self): + self.send_message('/x', 1)
+
+ + + +
+[docs] +class BonsaiRecordingMixin(BaseSession): + config: dict + +
+[docs] + def init_mixin_bonsai_recordings(self, *args, **kwargs): + self.bonsai_camera = Bunch({'udp_client': OSCClient(port=7111)}) + self.bonsai_microphone = Bunch({'udp_client': OSCClient(port=7112)}) + self.config = None # the name of the configuration to run
+ + +
+[docs] + def stop_mixin_bonsai_recordings(self): + log.info('Stopping Bonsai recordings') + self.bonsai_camera.udp_client.exit() + self.bonsai_microphone.udp_client.exit()
+ + +
+[docs] + def start_mixin_bonsai_microphone(self): + if not self.config: + # Use the first key in the device_cameras map + self.config = next((k for k in self.hardware_settings.device_cameras), None) + # The camera workflow on the behaviour computer already contains the microphone recording + # so the device camera workflow and the microphone one are exclusive + if self.config: + return # Camera workflow defined; so no need to separately start microphone. + if not self.task_params.RECORD_SOUND: + return # Sound should not be recorded + workflow_file = self.paths.IBLRIG_FOLDER.joinpath(*self.hardware_settings.device_microphone['BONSAI_WORKFLOW'].parts) + parameters = { + 'FileNameMic': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_micData.raw.wav'), + 'RecordSound': self.task_params.RECORD_SOUND, + } + call_bonsai(workflow_file, parameters, wait=False, editor=False) + log.info('Bonsai microphone recording module loaded: OK')
+ + + @staticmethod + def _camera_mixin_bonsai_get_workflow_file(cameras: dict | None, name: str) -> Path | None: + """ + Returns the bonsai workflow file for the cameras from the hardware_settings.yaml file. + + Parameters + ---------- + cameras : dict + The hardware settings configuration. + name : {'setup', 'recording'} str + The workflow type. + + Returns + ------- + Path + The workflow path. + """ + if cameras is None: + return None + return cameras['BONSAI_WORKFLOW'][name] + +
+[docs] + def start_mixin_bonsai_cameras(self): + """ + Prepare the cameras. + + Starts the pipeline that aligns the camera focus with the desired borders of rig features. + The actual triggering of the cameras is done in the trigger_bonsai_cameras method. + """ + if not self.config: + # Use the first key in the device_cameras map + try: + self.config = next(k for k in self.hardware_settings.device_cameras) + except StopIteration: + return + configuration = self.hardware_settings.device_cameras[self.config] + if (workflow_file := self._camera_mixin_bonsai_get_workflow_file(configuration, 'setup')) is None: + return + + # enable trigger of cameras (so Bonsai can disable it again ... sigh) + if PYSPIN_AVAILABLE: + from iblrig.video_pyspin import enable_camera_trigger + + enable_camera_trigger(True) + + call_bonsai(workflow_file, wait=True) # TODO Parameterize using configuration cameras + log.info('Bonsai cameras setup module loaded: OK')
+ + +
+[docs] + def trigger_bonsai_cameras(self): + if not self.config: + # Use the first key in the device_cameras map + try: + self.config = next(k for k in self.hardware_settings.device_cameras) + except StopIteration: + return + configuration = self.hardware_settings.device_cameras[self.config] + if set(configuration.keys()) != {'BONSAI_WORKFLOW', 'left'}: + raise NotImplementedError + workflow_file = self._camera_mixin_bonsai_get_workflow_file(configuration, 'recording') + if workflow_file is None: + return + iblrig.path_helper.create_bonsai_layout_from_template(workflow_file) + # FIXME Use parameters in configuration map + parameters = { + 'FileNameLeft': self.paths.SESSION_FOLDER.joinpath('raw_video_data', '_iblrig_leftCamera.raw.avi'), + 'FileNameLeftData': self.paths.SESSION_FOLDER.joinpath('raw_video_data', '_iblrig_leftCamera.frameData.bin'), + 'FileNameMic': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_micData.raw.wav'), + 'RecordSound': self.task_params.RECORD_SOUND, + } + call_bonsai(workflow_file, parameters, wait=False, editor=False) + log.info('Bonsai camera recording process started')
+
+ + + +
+[docs] +class BonsaiVisualStimulusMixin(BaseSession): +
+[docs] + def init_mixin_bonsai_visual_stimulus(self, *args, **kwargs): + # camera 7111, microphone 7112 + self.bonsai_visual_udp_client = OSCClient(port=7110)
+ + +
+[docs] + def start_mixin_bonsai_visual_stimulus(self): + self.choice_world_visual_stimulus()
+ + +
+[docs] + def stop_mixin_bonsai_visual_stimulus(self): + log.info('Stopping Bonsai visual stimulus') + self.bonsai_visual_udp_client.exit()
+ + +
+[docs] + def send_trial_info_to_bonsai(self): + """ + Send the trial information to Bonsai via UDP. + + The OSC protocol is documented in iblrig.base_tasks.BonsaiVisualStimulusMixin + """ + bonsai_dict = { + k: self.trials_table[k][self.trial_num] + for k in self.bonsai_visual_udp_client.OSC_PROTOCOL + if k in self.trials_table.columns + } + + # reverse wheel contingency: if stim_reverse is True we invert stim_gain + if self.trials_table.get('stim_reverse', {}).get(self.trial_num, False): + bonsai_dict['stim_gain'] = -bonsai_dict['stim_gain'] + + self.bonsai_visual_udp_client.send2bonsai(**bonsai_dict) + log.debug(bonsai_dict)
+ + +
+[docs] + def run_passive_visual_stim(self, map_time='00:05:00', rate=0.1, sa_time='00:05:00'): + workflow_file = self.paths.VISUAL_STIM_FOLDER.joinpath('passiveChoiceWorld', 'passiveChoiceWorld_passive.bonsai') + file_output_rfm = self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_RFMapStim.raw.bin') + parameters = { + 'Stim.DisplayIndex': self.hardware_settings.device_screen['DISPLAY_IDX'], + 'Stim.SpontaneousActivity0.DueTime': sa_time, + 'Stim.ReceptiveFieldMappingStim.FileNameRFMapStim': file_output_rfm, + 'Stim.ReceptiveFieldMappingStim.MappingTime': map_time, + 'Stim.ReceptiveFieldMappingStim.Rate': rate, + } + map_seconds = pd.to_timedelta(map_time).seconds + sa_seconds = pd.to_timedelta(sa_time).seconds + log.info(f'Starting spontaneous activity ({sa_seconds} s) and RF mapping stims ({map_seconds} s)') + s = call_bonsai(workflow_file, parameters, editor=False) + log.info('Spontaneous activity and RF mapping stims finished') + return s
+ + +
+[docs] + def choice_world_visual_stimulus(self): + if self.task_params.VISUAL_STIMULUS is None: + return + workflow_file = self.paths.VISUAL_STIM_FOLDER.joinpath(self.task_params.VISUAL_STIMULUS) + parameters = { + 'Stim.DisplayIndex': self.hardware_settings.device_screen['DISPLAY_IDX'], + 'Stim.FileNameStimPositionScreen': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_stimPositionScreen.raw.csv'), + 'Stim.FileNameSyncSquareUpdate': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_syncSquareUpdate.raw.csv'), + 'Stim.FileNamePositions': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_encoderPositions.raw.ssv'), + 'Stim.FileNameEvents': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_encoderEvents.raw.ssv'), + 'Stim.FileNameTrialInfo': self.paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_encoderTrialInfo.raw.ssv'), + 'Stim.REPortName': self.hardware_settings.device_rotary_encoder['COM_ROTARY_ENCODER'], + 'Stim.sync_x': self.task_params.SYNC_SQUARE_X, + 'Stim.sync_y': self.task_params.SYNC_SQUARE_Y, + 'Stim.TranslationZ': -self.task_params.STIM_TRANSLATION_Z, # MINUS!! + } + call_bonsai(workflow_file, parameters, wait=False, editor=self.task_params.BONSAI_EDITOR, bootstrap=False) + log.info('Bonsai visual stimulus module loaded: OK')
+
+ + + +
+[docs] +class BpodMixin(BaseSession): + def _raise_on_undefined_softcode_handler(self, byte: int): + raise ValueError(f'No handler defined for softcode #{byte}') + +
+[docs] + def softcode_dictionary(self) -> OrderedDict[int, Callable]: + """ + Returns a softcode handler dict where each key corresponds to the softcode and each value to the + function to be called. + + This needs to be wrapped this way because + 1) we want to be able to inherit this and dynamically add softcode to the dictionry + 2) we need to provide the Task object (self) at run time to have the functions with static args + This is tricky as it is unclear if the task object is a copy or a reference when passed here. + + + Returns + ------- + OrderedDict[int, Callable] + Softcode dictionary + """ + softcode_dict = OrderedDict( + { + SOFTCODE.STOP_SOUND: self.sound['sd'].stop, + SOFTCODE.PLAY_TONE: lambda: self.sound['sd'].play(self.sound['GO_TONE'], self.sound['samplerate']), + SOFTCODE.PLAY_NOISE: lambda: self.sound['sd'].play(self.sound['WHITE_NOISE'], self.sound['samplerate']), + SOFTCODE.TRIGGER_CAMERA: getattr( + self, 'trigger_bonsai_cameras', lambda: self._raise_on_undefined_softcode_handler(SOFTCODE.TRIGGER_CAMERA) + ), + } + ) + return softcode_dict
+ + +
+[docs] + def init_mixin_bpod(self, *args, **kwargs): + self.bpod = Bpod()
+ + +
+[docs] + def stop_mixin_bpod(self): + self.bpod.close()
+ + +
+[docs] + def start_mixin_bpod(self): + if self.hardware_settings['device_bpod']['COM_BPOD'] is None: + raise ValueError( + 'The value for device_bpod:COM_BPOD in ' + 'settings/hardware_settings.yaml is null. Please ' + 'provide a valid port name.' + ) + disabled_ports = [x - 1 for x in self.hardware_settings['device_bpod']['DISABLE_BEHAVIOR_INPUT_PORTS']] + self.bpod = Bpod(self.hardware_settings['device_bpod']['COM_BPOD'], disable_behavior_ports=disabled_ports) + self.bpod.define_rotary_encoder_actions() + self.bpod.set_status_led(False) + assert self.bpod.is_connected + log.info('Bpod hardware module loaded: OK') + # make the bpod send spacer signals to the main sync clock for protocol discovery + self.send_spacers()
+ + +
+[docs] + def send_spacers(self): + log.info('Starting task by sending a spacer signal on BNC1') + sma = StateMachine(self.bpod) + Spacer().add_spacer_states(sma, next_state='exit') + self.bpod.send_state_machine(sma) + self.bpod.run_state_machine(sma) # Locks until state machine 'exit' is reached + return self.bpod.session.current_trial.export()
+
+ + + +
+[docs] +class Frame2TTLMixin(BaseSession): + """Frame 2 TTL interface for state machine.""" + +
+[docs] + def init_mixin_frame2ttl(self, *args, **kwargs): + pass
+ + +
+[docs] + def start_mixin_frame2ttl(self): + # todo assert calibration + if self.hardware_settings['device_frame2ttl']['COM_F2TTL'] is None: + raise ValueError( + 'The value for device_frame2ttl:COM_F2TTL in ' + 'settings/hardware_settings.yaml is null. Please ' + 'provide a valid port name.' + ) + Frame2TTL( + port=self.hardware_settings['device_frame2ttl']['COM_F2TTL'], + threshold_dark=self.hardware_settings['device_frame2ttl']['F2TTL_DARK_THRESH'], + threshold_light=self.hardware_settings['device_frame2ttl']['F2TTL_LIGHT_THRESH'], + ).close() + log.info('Frame2TTL: Thresholds set.')
+
+ + + +
+[docs] +class RotaryEncoderMixin(BaseSession): + """Rotary encoder interface for state machine.""" + +
+[docs] + def init_mixin_rotary_encoder(self, *args, **kwargs): + self.device_rotary_encoder = MyRotaryEncoder( + all_thresholds=self.task_params.STIM_POSITIONS + self.task_params.QUIESCENCE_THRESHOLDS, + gain=self.task_params.STIM_GAIN, + com=self.hardware_settings.device_rotary_encoder['COM_ROTARY_ENCODER'], + connect=False, + )
+ + +
+[docs] + def start_mixin_rotary_encoder(self): + if self.hardware_settings['device_rotary_encoder']['COM_ROTARY_ENCODER'] is None: + raise ValueError( + 'The value for device_rotary_encoder:COM_ROTARY_ENCODER in ' + 'settings/hardware_settings.yaml is null. Please ' + 'provide a valid port name.' + ) + try: + self.device_rotary_encoder.connect() + except serial.serialutil.SerialException as e: + raise serial.serialutil.SerialException( + f'The rotary encoder COM port {self.device_rotary_encoder.RE_PORT} is already in use. This is usually' + f' due to a Bonsai process currently running on the computer. Make sure all Bonsai windows are' + f' closed prior to running the task' + ) from e + except Exception as e: + raise Exception( + "The rotary encoder couldn't connect. If the bpod is glowing in green," + 'disconnect and reconnect bpod from the computer' + ) from e + log.info('Rotary encoder module loaded: OK')
+
+ + + +
+[docs] +class ValveMixin(BaseSession, HasBpod): +
+[docs] + def init_mixin_valve(self: object): + self.valve = Valve(self.hardware_settings.device_valve)
+ + +
+[docs] + def start_mixin_valve(self): + # assert that valve has been calibrated + assert self.valve.is_calibrated, """VALVE IS NOT CALIBRATED - PLEASE CALIBRATE THE VALVE""" + + # regardless of the calibration method, the reward valve time has to be lower than 1 second + assert self.compute_reward_time(amount_ul=1.5) < 1, """VALVE IS NOT PROPERLY CALIBRATED - PLEASE RECALIBRATE""" + log.info('Water valve module loaded: OK')
+ + +
+[docs] + def compute_reward_time(self, amount_ul: float | None = None) -> float: + """ + Converts the valve opening time from a given volume. + + Parameters + ---------- + amount_ul : float, optional + The volume of liquid (μl) to be dispensed from the valve. Defaults to task_params.REWARD_AMOUNT_UL. + + Returns + ------- + float + Valve opening time in seconds. + """ + amount_ul = self.task_params.REWARD_AMOUNT_UL if amount_ul is None else amount_ul + return self.valve.values.ul2ms(amount_ul) / 1e3
+ + +
+[docs] + def valve_open(self, reward_valve_time): + """ + Open the reward valve for a given amount of time and return bpod data. + + Parameters + ---------- + reward_valve_time : float + Amount of time in seconds to open the reward valve. + """ + sma = StateMachine(self.bpod) + sma.add_state( + state_name='valve_open', + state_timer=reward_valve_time, + output_actions=[('Valve1', 255), ('BNC1', 255)], # To FPGA + state_change_conditions={'Tup': 'exit'}, + ) + self.bpod.send_state_machine(sma) + self.bpod.run_state_machine(sma) # Locks until state machine 'exit' is reached + return self.bpod.session.current_trial.export()
+
+ + + +
+[docs] +class SoundMixin(BaseSession, HasBpod): + """Sound interface methods for state machine.""" + +
+[docs] + def init_mixin_sound(self): + self.sound = Bunch({'GO_TONE': None, 'WHITE_NOISE': None}) + sound_output = self.hardware_settings.device_sound['OUTPUT'] + + # additional gain factor for bringing the different combinations of sound-cards and amps to the same output level + # TODO: this needs proper calibration and refactoring + if self.hardware_settings.device_sound.OUTPUT == 'hifi' and self.hardware_settings.device_sound.AMP_TYPE == 'AMP2X15': + amp_gain_factor = 0.25 + else: + amp_gain_factor = 1.0 + self.task_params.GO_TONE_AMPLITUDE *= amp_gain_factor + self.task_params.WHITE_NOISE_AMPLITUDE *= amp_gain_factor + + # sound device sd is actually the module soundevice imported above. + # not sure how this plays out when referenced outside of this python file + self.sound['sd'], self.sound['samplerate'], self.sound['channels'] = sound_device_factory(output=sound_output) + # Create sounds and output actions of state machine + self.sound['GO_TONE'] = iblrig.sound.make_sound( + rate=self.sound['samplerate'], + frequency=self.task_params.GO_TONE_FREQUENCY, + duration=self.task_params.GO_TONE_DURATION, + amplitude=self.task_params.GO_TONE_AMPLITUDE * amp_gain_factor, + fade=0.01, + chans=self.sound['channels'], + ) + self.sound['WHITE_NOISE'] = iblrig.sound.make_sound( + rate=self.sound['samplerate'], + frequency=-1, + duration=self.task_params.WHITE_NOISE_DURATION, + amplitude=self.task_params.WHITE_NOISE_AMPLITUDE * amp_gain_factor, + fade=0.01, + chans=self.sound['channels'], + )
+ + +
+[docs] + def start_mixin_sound(self): + """ + Depends on bpod mixin start for hard sound card + :return: + """ + assert self.bpod.is_connected, 'The sound mixin depends on the bpod mixin being connected' + # SoundCard config params + match self.hardware_settings.device_sound['OUTPUT']: + case 'harp': + assert self.bpod.sound_card is not None, 'No harp sound-card connected to Bpod' + sound.configure_sound_card( + sounds=[self.sound.GO_TONE, self.sound.WHITE_NOISE], + indexes=[self.task_params.GO_TONE_IDX, self.task_params.WHITE_NOISE_IDX], + sample_rate=self.sound['samplerate'], + ) + self.bpod.define_harp_sounds_actions( + module=self.bpod.sound_card, + go_tone_index=self.task_params.GO_TONE_IDX, + noise_index=self.task_params.WHITE_NOISE_IDX, + ) + case 'hifi': + module = self.bpod.get_module('^HiFi') + assert module is not None, 'No HiFi module connected to Bpod' + assert self.hardware_settings.device_sound.COM_SOUND is not None + hifi = HiFi(port=self.hardware_settings.device_sound.COM_SOUND, sampling_rate_hz=self.sound['samplerate']) + hifi.load(index=self.task_params.GO_TONE_IDX, data=self.sound.GO_TONE) + hifi.load(index=self.task_params.WHITE_NOISE_IDX, data=self.sound.WHITE_NOISE) + hifi.push() + hifi.close() + self.bpod.define_harp_sounds_actions( + module=module, + go_tone_index=self.task_params.GO_TONE_IDX, + noise_index=self.task_params.WHITE_NOISE_IDX, + ) + case _: + self.bpod.define_xonar_sounds_actions() + log.info(f"Sound module loaded: OK: {self.hardware_settings.device_sound['OUTPUT']}")
+ + +
+[docs] + def sound_play_noise(self, state_timer=0.510, state_name='play_noise'): + """ + Play the noise sound for the error feedback using bpod state machine. + :return: bpod current trial export + """ + return self._sound_play(state_name=state_name, output_actions=[self.bpod.actions.play_tone], state_timer=state_timer)
+ + +
+[docs] + def sound_play_tone(self, state_timer=0.102, state_name='play_tone'): + """ + Play the ready tone beep using bpod state machine. + :return: bpod current trial export + """ + return self._sound_play(state_name=state_name, output_actions=[self.bpod.actions.play_tone], state_timer=state_timer)
+ + + def _sound_play(self, state_timer=None, output_actions=None, state_name='play_sound'): + """Plays a sound using bpod state machine. + + The sound must be defined in the init_mixin_sound method. + """ + assert state_timer is not None, 'state_timer must be defined' + assert output_actions is not None, 'output_actions must be defined' + sma = StateMachine(self.bpod) + sma.add_state( + state_name=state_name, + state_timer=state_timer, + output_actions=[self.bpod.actions.play_tone], + state_change_conditions={'BNC2Low': 'exit', 'Tup': 'exit'}, + ) + self.bpod.send_state_machine(sma) + self.bpod.run_state_machine(sma) # Locks until state machine 'exit' is reached + return self.bpod.session.current_trial.export()
+ + + +
+[docs] +class NetworkSession(BaseSession): + """A mixin for communicating to auxiliary acquisition PC over a network.""" + + remote_rigs = None + """net.Auxiliaries: An auxiliary services object for communicating with remote devices.""" + exp_ref = None + """dict: The experiment reference (i.e. subject, date, sequence) as returned by main remote service.""" + +
+[docs] + def __init__(self, *_, remote_rigs=None, **kwargs): + """ + A mixin for communicating to auxiliary acquisition PC over a network. + + This should retrieve the services list, i.e. the list of available auxiliary rigs, + and determine which is the main sync. The main sync is the rig that determines the + experiment. + + The services list is in a yaml file somewhere, called 'remote_rigs.yaml' and should + be a map of device name to URI. These are then selectable in the GUI and the URI of + those selected are added to the experiment description. + + Subclasses should add their callbacks within init by calling :meth:`self.remote_rigs.services.assign_callback`. + + Parameters + ---------- + remote_rigs : list, dict + Either a list of remote device names (in which case URI is looked up from remote devices + file), or a map of device name to URI. + kwargs + Optional args such as 'file_iblrig_settings' for defining location of remote data folder + when loading remote devices file. + """ + if isinstance(remote_rigs, list): + # For now we flatten to list of remote rig names but could permit list of (name, URI) tuples + remote_rigs = list(filter(None, flatten(remote_rigs))) + all_remote_rigs = net.get_remote_devices(iblrig_settings=kwargs.get('iblrig_settings', None)) + if not set(remote_rigs).issubset(all_remote_rigs.keys()): + raise ValueError('Selected remote rigs not in remote rigs list') + remote_rigs = {k: v for k, v in all_remote_rigs.items() if k in remote_rigs} + # Load and connect to remote services + self.connect(remote_rigs) + self.exp_ref = {} + try: + super().__init__(**kwargs) + except Exception as ex: + self.cleanup_mixin_network() + raise ex
+ + + @property + def one(self): + """Return ONE instance. + + Unlike super class getter, this method will always instantiate ONE, allowing subclasses to update with an Alyx + token from a remotely connected rig. This instance is used for formatting the experiment reference string. + + Returns + ------- + one.api.One + An instance of ONE. + """ + if super().one is None: + self._one = OneAlyx(silent=True, mode='local') + return self._one + +
+[docs] + def connect(self, remote_rigs): + """ + Connect to remote services. + + Instantiates the Communicator objects that establish connections with each remote device. + This also creates the thread that uses asynchronous callbacks. + + Parameters + ---------- + remote_rigs : dict + A map of name to URI. + """ + self.remote_rigs = net.Auxiliaries(remote_rigs or {}) + assert not remote_rigs or self.remote_rigs.is_connected + # Handle termination event by graciously completing thread + signal.signal(signal.SIGTERM, lambda sig, frame: self.cleanup_mixin_network())
+ + + def _init_paths(self, append: bool = False): + """ + Determine session paths. + + Unlike :meth:`BaseSession._init_paths`, this method determines the session number from the remote main sync if + connected. + + Parameters + ---------- + append : bool + Iterate task collection within today's most recent session folder for the selected subject, instead of + iterating session number. + + Returns + ------- + iblutil.util.Bunch + A bunch of paths. + """ + if self.hardware_settings.MAIN_SYNC: + return BaseSession._init_paths(self, append) + # Check if we have rigs connected + if not self.remote_rigs.is_connected: + log.warning('No remote rigs; experiment reference may not match the main sync.') + return BaseSession._init_paths(self, append) + # Set paths in a similar way to the super class + rig_computer_paths = iblrig.path_helper.get_local_and_remote_paths( + local_path=self.iblrig_settings['iblrig_local_data_path'], + remote_path=self.iblrig_settings['iblrig_remote_data_path'], + lab=self.iblrig_settings['ALYX_LAB'], + iblrig_settings=self.iblrig_settings, + ) + paths = Bunch({'IBLRIG_FOLDER': BASE_PATH}) + paths.BONSAI = BONSAI_EXE + paths.VISUAL_STIM_FOLDER = paths.IBLRIG_FOLDER.joinpath('visual_stim') + paths.LOCAL_SUBJECT_FOLDER = rig_computer_paths['local_subjects_folder'] + paths.REMOTE_SUBJECT_FOLDER = rig_computer_paths['remote_subjects_folder'] + date_folder = paths.LOCAL_SUBJECT_FOLDER.joinpath( + self.session_info.SUBJECT_NAME, self.session_info.SESSION_START_TIME[:10] + ) + assert self.exp_ref + paths.SESSION_FOLDER = date_folder / f'{self.exp_ref["sequence"]:03}' + paths.TASK_COLLECTION = iblrig.path_helper.iterate_collection(paths.SESSION_FOLDER) + if append == paths.TASK_COLLECTION.endswith('00'): + raise ValueError( + f'Append value incorrect. Either remove previous task collections from ' + f'{paths.SESSION_FOLDER}, or select append in GUI (--append arg in cli)' + ) + + paths.SESSION_RAW_DATA_FOLDER = paths.SESSION_FOLDER.joinpath(paths.TASK_COLLECTION) + paths.DATA_FILE_PATH = paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_taskData.raw.jsonable') + paths.SETTINGS_FILE_PATH = paths.SESSION_RAW_DATA_FOLDER.joinpath('_iblrig_taskSettings.raw.json') + self.session_info.SESSION_NUMBER = int(paths.SESSION_FOLDER.name) + return paths + +
+[docs] + def run(self): + """Run session and report exceptions to remote services.""" + self.start_mixin_network() + try: + return super().run() + except Exception as e: + # Communicate error to services + if self.remote_rigs.is_connected: + tb = e.__traceback__ # TODO maybe go one level down with tb_next? + details = { + 'error': e.__class__.__name__, # exception name str + 'message': str(e), # error str + 'traceback': traceback.format_exc(), # stack str + 'file': tb.tb_frame.f_code.co_filename, # filename str + 'line_no': (tb.tb_lineno, tb.tb_lasti), # (int, int) + } + self.remote_rigs.push(ExpMessage.EXPINTERRUPT, details, wait=True) + self.cleanup_mixin_network() + raise e
+ + +
+[docs] + def communicate(self, message, *args, raise_on_exception=True): + """ + Communicate message to remote services. + + This method is blocking and by default will raise if not all responses received in time. + + Parameters + ---------- + message : iblutil.io.net.base.ExpMessage, str, int + An experiment message to send to remote services. + args + One or more optional variables to send. + raise_on_exception : bool + If true, exceptions arising from message timeouts will be re-raised in main thread and + services will be cleaned up. Only applies when wait is true. + + Returns + ------- + Exception | dict + If raise_on_exception is False, returns an exception if failed to receive all responses + in time, otherwise a map of service name to response is returned. + """ + r = self.remote_rigs.push(message, *args, wait=True) + if isinstance(r, Exception): + log.error('Error on %s network mixin: %s', message, r) + if raise_on_exception: + self.cleanup_mixin_network() + raise r + return r
+ + +
+[docs] + def get_exp_info(self): + ref = self.exp_ref or None + if isinstance(ref, dict) and self.one: + ref = self.one.dict2ref(ref) + is_main_sync = self.hardware_settings.get('MAIN_SYNC', False) + info = net.ExpInfo(ref, is_main_sync, self.experiment_description, master=is_main_sync) + return info.to_dict()
+ + +
+[docs] + def init_mixin_network(self): + """Initialize remote services. + + This method sends an EXPINFO message to all services, expecting exactly one of the responses + to contain main_sync: True, along with the experiment reference to use. It then sends an + EXPINIT message to all services. + """ + if not self.remote_rigs.is_connected: + return + # Determine experiment reference from main sync + is_main_sync = self.hardware_settings.get('MAIN_SYNC', False) + if is_main_sync: + raise NotImplementedError + assert self.one + + expinfo = self.get_exp_info() | {'subject': self.session_info['SUBJECT_NAME']} + r = self.communicate('EXPINFO', 'CONNECTED', expinfo) + assert sum(x[-1]['main_sync'] for x in r.values()) == 1, 'one main sync expected' + main_rig_name, (status, info) = next((k, v) for k, v in r.items() if v[-1]['main_sync']) + self.exp_ref = self.one.ref2dict(info['exp_ref']) if isinstance(info['exp_ref'], str) else info['exp_ref'] + if self.exp_ref['subject'] != self.session_info['SUBJECT_NAME']: + log.error( + 'Running task for "%s" but main sync returned exp ref for "%s".', + self.session_info['SUBJECT_NAME'], + self.exp_ref['subject'], + ) + raise ValueError("Subject name doesn't match remote session on " + main_rig_name) + if str(self.exp_ref['date']) != self.session_info['SESSION_START_TIME'][:10]: + raise RuntimeError( + f'Session dates do not match between this rig and {main_rig_name}. \n' + f'Running past or future sessions not currently supported. \n' + f'Please check the system date time settings on each rig.' + ) + + # exp_ref = ConversionMixin.path2ref(self.paths['SESSION_FOLDER'], as_dict=False) + exp_ref = self.one.dict2ref(self.exp_ref) + self.communicate('EXPINIT', {'exp_ref': exp_ref})
+ + +
+[docs] + def start_mixin_network(self): + """Start remote services. + + This method sends an EXPSTART message to all services, along with an exp_ref string. + Responses are required but ignored. + """ + if not self.remote_rigs.is_connected: + return + self.communicate('EXPSTART', self.exp_ref)
+ + +
+[docs] + def stop_mixin_network(self): + """Start remote services. + + This method sends an EXPEND message to all services. Responses are required but ignored. + """ + if not self.remote_rigs.is_connected: + return + self.communicate('EXPEND')
+ + +
+[docs] + def cleanup_mixin_network(self): + """Clean up services.""" + self.remote_rigs.close() + if self.remote_rigs.is_connected: + log.warning('Failed to properly clean up network mixin')
+
+ + + +
+[docs] +class SpontaneousSession(BaseSession): + """ + A Spontaneous task doesn't have trials, it just runs until the user stops it. + + It is used to get extraction structure for data streams + """ + +
+[docs] + def __init__(self, duration_secs=None, **kwargs): + super().__init__(**kwargs) + self.duration_secs = duration_secs
+ + +
+[docs] + def start_hardware(self): + pass # no mixin here, life is but a dream
+ + + def _run(self): + """Run the task with the actual state machine.""" + log.info('Starting spontaneous acquisition') + while True: + time.sleep(1.5) + if self.duration_secs is not None and self.time_elapsed.seconds > self.duration_secs: + break + if self.paths.SESSION_FOLDER.joinpath('.stop').exists(): + self.paths.SESSION_FOLDER.joinpath('.stop').unlink() + break
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/choiceworld.html b/_modules/iblrig/choiceworld.html new file mode 100644 index 000000000..e69cd98ec --- /dev/null +++ b/_modules/iblrig/choiceworld.html @@ -0,0 +1,320 @@ + + + + + + iblrig.choiceworld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.choiceworld

+"""
+Choice World Task related logic and functions that translate the task description in
+Appendix 2 of the paper into code.
+"""
+
+import logging
+from typing import Literal
+
+import numpy as np
+
+import iblrig.raw_data_loaders
+from iblrig.path_helper import iterate_previous_sessions
+
+log = logging.getLogger(__name__)
+
+CONTRASTS = 1 / np.array([-1, -2, -4, -8, -16, np.inf, 16, 8, 4, 2, 1])
+DEFAULT_TRAINING_PHASE = 0
+DEFAULT_REWARD_VOLUME = 3.0
+
+
+
+[docs] +def compute_adaptive_reward_volume(subject_weight_g, reward_volume_ul, delivered_volume_ul, ntrials): + """ + If the mouse completed over 200 trials in the previous session, the reward volume is automatically + lowered by 0.1 microliters for the next session, but cannot go lower than a floor of 1.5 microliters. + If the mouse received less than its minimum required daily dose (~1 milliliter/25 grams of body weight) + during the previous session, the reward volume is increased by 0.1 microliters for the next session, + but cannot go above a ceiling of 3 microliters. + :param subject_weight_g: in grams + :param reward_volume_ul: the last reward volume setting in uL + :param delivered_volume_ul: the cumulative water deliverd during the last session in uL + :param n_trials: + :return: adaptive_reward_ul + """ + if subject_weight_g > (delivered_volume_ul / 1000 * 25): + reward_volume_ul += 0.1 + elif ntrials > 200: + reward_volume_ul -= 0.1 + return np.maximum(np.minimum(reward_volume_ul, 3), 1.5)
+ + + +
+[docs] +def get_subject_training_info( + subject_name: str, + task_name: str = '_iblrig_tasks_trainingChoiceWorld', + stim_gain: float | None = None, + stim_gain_on_error: float | None = None, + default_reward: float = DEFAULT_REWARD_VOLUME, + mode: Literal['silent', 'raise'] = 'silent', + **kwargs, +) -> tuple[dict, dict | None]: + """ + Goes through a subject's history and gets the latest training phase and adaptive reward volume. + + Parameters + ---------- + subject_name : str + Name of the subject. + task_name : str, optional + Name of the protocol to look for in experiment description, defaults to '_iblrig_tasks_trainingChoiceWorld'. + stim_gain: float, optional + Default stimulus gain if no previous session is available, default to None + stim_gain_on_error: float, optional + Default stimulus gain if there was an exception whilst obtaining the previous sessions' info, default to None + default_reward : float, optional + Default reward volume in uL if no previous session is available. + mode : str, optional + If 'silent' returns default values if no history is found, if 'raise' raises ValueError. + **kwargs + Optional arguments to be passed to get_local_and_remote_paths + + Returns + ------- + training_info: dict + Dictionary with keys: training_phase, adaptive_reward, adaptive_gain + session_info: dict or None + Dictionary with keys: session_path, experiment_description, task_settings, file_task_data + """ + # default values (if no previous session is available) + training_info = { + 'training_phase': DEFAULT_TRAINING_PHASE, + 'adaptive_reward': default_reward, + 'adaptive_gain': stim_gain, + } + + # try to obtain the subject's previous session's info + try: + session_info = iterate_previous_sessions(subject_name, task_name=task_name, n=1, **kwargs) + if len(session_info) > 0: + session_info = session_info[0] + task_settings = session_info.get('task_settings') + trials_data, _ = iblrig.raw_data_loaders.load_task_jsonable(session_info.get('file_task_data')) + except Exception as e: + log.exception(msg='Error obtaining training information from previous session!', exc_info=e) + training_info['adaptive_gain'] = stim_gain_on_error + session_info = [] + + # handle lack of previous sessions + if len(session_info) == 0: + if mode == 'silent': + log.warning( + f"Could not determine training status for subject '{subject_name}' - returning default values " + f'(training phase: {training_info["training_phase"]}, adaptive reward: ' + f'{training_info["adaptive_reward"]}, adaptive gain: {training_info["adaptive_gain"]})' + ) + return training_info, None + else: + raise ValueError(f'The training status for {subject_name} could not be determined as no previous sessions were found') + + # compute reward volume from previous session + prev_reward_vol = task_settings.get('ADAPTIVE_REWARD_AMOUNT_UL') or task_settings.get('REWARD_AMOUNT_UL') + training_info['adaptive_reward'] = compute_adaptive_reward_volume( + subject_weight_g=task_settings.get('SUBJECT_WEIGHT'), + reward_volume_ul=prev_reward_vol, + delivered_volume_ul=trials_data.get('reward_amount').sum(), + ntrials=trials_data.shape[0], + ) + + # retrieve training_phase from the previous session's trials table + if 'training_phase' in trials_data: + training_info['training_phase'] = trials_data['training_phase'].values[-1] + + # set adaptive gain depending on number of correct trials in previous session. + # also fix negative adaptive gain values (due to a bug in the GUI prior to v8.21.0 + if np.sum(trials_data['response_side'] != 0) > 200: + training_info['adaptive_gain'] = task_settings.get('STIM_GAIN') + elif task_settings.get('ADAPTIVE_GAIN_VALUE', 1) < 0: + training_info['adaptive_gain'] = task_settings.get('AG_INIT_VALUE') + else: + training_info['adaptive_gain'] = task_settings.get('ADAPTIVE_GAIN_VALUE', task_settings.get('AG_INIT_VALUE')) + + return training_info, session_info
+ + + +
+[docs] +def training_contrasts_probabilities(phase=1): + match phase: + case 0: # Starts with only 100% and 50% contrasts. + frequencies = np.abs(CONTRASTS) >= 0.5 + case 1: # The 25% contrast is added to the set. + frequencies = np.abs(CONTRASTS) >= 0.25 + case 2: # The 12.5% contrast is added to the set. + frequencies = np.abs(CONTRASTS) >= 0.125 + case 3: # The 6.25% contrast is added to the set. + frequencies = np.abs(CONTRASTS) >= 0.0625 + case 4: # The 0% contrast is added to the set. + frequencies = np.abs(CONTRASTS) >= 0 + case 5: # The 50% contrast is removed from the set + frequencies = np.abs(CONTRASTS) != 0.5 + return frequencies / np.sum(frequencies)
+ + + +
+[docs] +def draw_training_contrast(phase: int) -> float: + probabilities = training_contrasts_probabilities(phase) + return np.random.choice(CONTRASTS, p=probabilities)
+ + + +
+[docs] +def contrasts_set(phase: int) -> np.array: + probabilities = training_contrasts_probabilities(phase) + return CONTRASTS[probabilities > 0]
+ + + +
+[docs] +def training_phase_from_contrast_set(contrast_set: list[float]) -> int | None: + contrast_set = sorted(contrast_set) + for phase in range(6): + expected_set = CONTRASTS[np.logical_and(training_contrasts_probabilities(phase) > 0, CONTRASTS >= 0)] + if np.array_equal(contrast_set, expected_set): + return phase + raise Exception(f'Could not determine training phase from contrast set {contrast_set}')
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/commands.html b/_modules/iblrig/commands.html new file mode 100644 index 000000000..8e3b3a202 --- /dev/null +++ b/_modules/iblrig/commands.html @@ -0,0 +1,522 @@ + + + + + + iblrig.commands — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.commands

+import argparse
+import datetime
+import logging
+import shutil
+import warnings
+from collections.abc import Iterable
+from pathlib import Path
+
+import yaml
+
+import iblrig
+from iblrig.hardware import Bpod
+from iblrig.online_plots import OnlinePlots
+from iblrig.path_helper import get_local_and_remote_paths
+from iblrig.transfer_experiments import BehaviorCopier, EphysCopier, SessionCopier, VideoCopier
+from iblutil.util import setup_logger
+
+logger = logging.getLogger(__name__)
+
+
+tag2copier = {'behavior': BehaviorCopier, 'video': VideoCopier, 'ephys': EphysCopier}
+
+
+def _transfer_parser(description: str) -> argparse.ArgumentParser:
+    """
+    Create an ArgumentParser for transfer scripts.
+
+    This function creates an ArgumentParser object with specific arguments for a
+    script related to data transfer. It defines command-line arguments for
+    defining local and remote data paths and enabling the dry run mode.
+
+    Parameters
+    ----------
+    description : str
+        A brief description of the script's purpose.
+
+    Returns
+    -------
+    argparse.ArgumentParser
+        An ArgumentParser object with pre-defined arguments.
+    """
+    parser = argparse.ArgumentParser(
+        description=description, formatter_class=argparse.ArgumentDefaultsHelpFormatter, argument_default=argparse.SUPPRESS
+    )
+    parser.add_argument('-t', '--tag', default='behavior', type=str, help='data type to transfer, e.g. "behavior", "video"')
+    parser.add_argument('-l', '--local', action='store', type=dir_path, dest='local_path', help='define local data path')
+    parser.add_argument('-r', '--remote', action='store', type=dir_path, dest='remote_path', help='define remote data path')
+    parser.add_argument('-d', '--dry', action='store_true', dest='dry', help='do not remove local data after copying')
+    parser.add_argument(
+        '-c', '--cleanup-weeks', type=int, help='cleanup data older than this many weeks (-1 for no cleanup)', default=2
+    )
+    parser.add_argument(
+        '-s', '--subject', type=str, help='an optional subject name to filter sessions by. Wildcards accepted.', default='*'
+    )
+    parser.add_argument(
+        '--date', type=str, help='an optional date pattern to filter sessions by. Wildcards accepted.', default='*-*-*'
+    )
+    return parser
+
+
+
+[docs] +def dir_path(directory: str) -> Path: + """ + Convert a string to a Path object and check if the directory exists. + + This function is intended for use as a type conversion function with argparse. + It takes a string argument representing a directory path, converts it into + a Path object, and checks if the directory exists. If the directory exists, + it returns the Path object; otherwise, it raises an argparse.ArgumentError + with an appropriate error message. + + Parameters + ---------- + directory : str + A string representing a directory path. + + Returns + ------- + pathlib.Path + A Path object representing the directory. + + Raises + ------ + argparse.ArgumentError + If the directory does not exist, an argparse.ArgumentError is raised + with an error message indicating that the directory was not found. + """ + directory = Path(directory) + if directory.exists(): + return directory + raise argparse.ArgumentError(None, f'Directory `{directory}` not found')
+ + + +
+[docs] +def transfer_data_cli(): + """Command-line interface for transferring behavioral data to the local server.""" + setup_logger('iblrig', level='INFO') + args = _transfer_parser('Copy data to the local server.').parse_args() + transfer_data(**vars(args), interactive=True)
+ + + +
+[docs] +def transfer_video_data_cli(): + """Command-line interface for transferring video data to the local server.""" + setup_logger('iblrig', level='INFO') + warnings.warn( + 'transfer_video_data will be removed in the future. Use "transfer_data video" instead.', FutureWarning, stacklevel=2 + ) + args = _transfer_parser('Copy video data to the local server.').parse_args() + transfer_data(**{**vars(args), 'tag': 'video'}, interactive=True)
+ + + +
+[docs] +def transfer_ephys_data_cli(): + """Command-line interface for transferring ephys data to the local server.""" + setup_logger('iblrig', level='INFO') + warnings.warn( + 'transfer_ephys_data will be removed in the future. Use "transfer_data ephys" instead.', FutureWarning, stacklevel=2 + ) + args = _transfer_parser('Copy ephys data to the local server.').parse_args() + transfer_data(**{**vars(args), 'tag': 'ephys'}, interactive=True)
+ + + +def _get_subjects_folders(local_path: Path, remote_path: Path) -> tuple[Path, Path]: + rig_paths = get_local_and_remote_paths(local_path, remote_path) + local_path = rig_paths.local_subjects_folder + remote_path = rig_paths.remote_subjects_folder + assert isinstance(local_path, Path) + if remote_path is None: + raise Exception('Remote Path is not defined.') + return local_path, remote_path + + +def _get_copiers( + copier: type[SessionCopier], + local_folder: Path, + remote_folder: Path, + lab: str = None, + glob_pattern: str = '*/????-??-??/*/transfer_me.flag', + interactive: bool = False, + **kwargs, +) -> list[SessionCopier]: + """ + + Parameters + ---------- + copier : SessionCopier + A SessionCopier class to instantiate for each session. + local_folder : str + The absolute path of the local data directory (the copy root source). If None, loads from + the iblrig settings file. + remote_folder : str + The absolute path of the remote data directory (the copy root destination). If None, loads + from the iblrig settings file. + lab : str + The name of the lab. Only used if 'iblrig_local_subjects_path' is not defined in the + settings file. If None, uses 'ALYX_LAB' field of iblrig settings. + glob_pattern : str + The filename to recursively search within `local_folder` for determining which sessions to + copy. + interactive : bool + If true, users are prompted to review the sessions to copy before proceeding. + kwargs + Extract arguments such as `tag` to pass to the SessionCopier. + + Returns + ------- + list of SessionCopier + A list of SessionCopier objects. + """ + # get local/remote subjects folder + rig_paths = get_local_and_remote_paths(local_path=local_folder, remote_path=remote_folder, lab=lab) + local_subjects_folder = local_folder or rig_paths.local_subjects_folder + remote_subjects_folder = remote_folder or rig_paths.remote_subjects_folder + assert isinstance(local_subjects_folder, Path) + if remote_subjects_folder is None: + raise Exception('Remote Path is not defined.') + level = logging.INFO if interactive else logging.DEBUG + logger.log(level, 'Local Path: %s', local_subjects_folder) + logger.log(level, 'Remote Path: %s', remote_subjects_folder) + + # get copiers + copiers = [copier(f.parent, remote_subjects_folder, **kwargs) for f in local_subjects_folder.glob(glob_pattern)] + if len(copiers) == 0: + print('Could not find any sessions to copy to the local server.') + elif interactive: + _print_status(copiers, 'Session states prior to transfer operation:') + if input('\nDo you want to continue? [Y/n] ').lower() not in ('y', ''): + copiers = [] + return copiers + + +def _print_status(copiers: Iterable[SessionCopier], heading: str = '') -> None: + print(heading) + for copier in copiers: + match copier.state: + case 0: + state = 'not registered on server' + case 1: + state = 'copy pending' + case 2: + state = 'copy complete' + case 3: + state = 'copy finalized' + case _: + state = 'undefined' + print(f' * {copier.session_path}: {state}') + + +def _build_glob_pattern(subject='*', date='*-*-*', number='*', flag_file='transfer_me.flag', **kwargs): + """ + Build the copier glob pattern from filter keyword arguments. + + Parameters + ---------- + subject : str + A subject folder filter pattern. + date : str + A date folder pattern. + number : str + A number (i.e. experiment sequence) folder pattern. + flag_file : str + A flag filename pattern. + glob_pattern : str + The full glob pattern string (if defined, overrides all other arguments). + + Returns + ------- + str + The full glob pattern. + """ + return kwargs.get('glob_pattern', '/'.join((subject, date, number, flag_file))) + + +
+[docs] +def transfer_data( + tag=None, + local_path: Path = None, + remote_path: Path = None, + dry: bool = False, + interactive: bool = False, + cleanup_weeks=2, + **kwargs, +) -> list[SessionCopier]: + """ + Copies data from the rig to the local server. + + Parameters + ---------- + tag : str + The acquisition PC tag to transfer, e.g. 'behavior', 'video', 'ephys', 'timeline', etc. + local_path : Path + Path to local subjects folder, otherwise fetches path from iblrig_settings.yaml file. + remote_path : Path + Path to remote subjects folder, otherwise fetches path from iblrig_settings.yaml file. + dry : bool + Do not copy or remove local data. + interactive : bool + If true, users are prompted to review the sessions to copy before proceeding. + cleanup_weeks : int, bool + Remove local data older than this number of weeks. If False, do not remove. + kwargs + Optional arguments to pass to SessionCopier constructor. + + Returns + ------- + list of SessionCopier + A list of the copier objects that were run. + """ + if not tag: + raise ValueError('Tag required.') + # Build glob patten based on subject/date/number/flag_file filter + kwargs['glob_pattern'] = _build_glob_pattern(**kwargs) + kwargs = {k: v for k, v in kwargs.items() if k not in ('subject', 'date', 'number', 'flag_file')} + local_subject_folder, remote_subject_folder = _get_subjects_folders(local_path, remote_path) + copier = tag2copier.get(tag.lower(), SessionCopier) + logger.info('Searching for %s sessions using %s class', tag.lower(), copier.__name__) + expected_devices = kwargs.pop('number_of_expected_devices', None) + copiers = _get_copiers(copier, local_subject_folder, remote_subject_folder, interactive=interactive, tag=tag, **kwargs) + + for copier in copiers: + logger.critical(f'{copier.state}, {copier.session_path}') + if not dry: + copier.run(number_of_expected_devices=expected_devices) + + if interactive: + _print_status(copiers, 'States after transfer operation:') + + # once we copied the data, remove older session for which the data was successfully uploaded + if isinstance(cleanup_weeks, int) and cleanup_weeks > -1: + remove_local_sessions( + weeks=cleanup_weeks, dry=dry, local_path=local_subject_folder, remote_path=remote_subject_folder, tag=tag + ) + return copiers
+ + + +
+[docs] +def remove_local_sessions(weeks=2, local_path=None, remote_path=None, dry=False, tag='behavior'): + """ + Remove local sessions older than N weeks. + + Parameters + ---------- + weeks : int + Remove local sessions older than this number of weeks. + local_path : Path + Path to local subjects folder, otherwise fetches path from iblrig_settings.yaml file. + remote_path : Path + Path to remote subjects folder, otherwise fetches path from iblrig_settings.yaml file. + dry : bool + Do not remove local data if True. + tag : str + The acquisition PC tag to transfer, e.g. 'behavior', 'video', 'ephys', 'timeline', etc. + + Returns + ------- + list of Path + A list of removed session paths. + """ + local_subject_folder, remote_subject_folder = _get_subjects_folders(local_path, remote_path) + size = 0 + copier = tag2copier.get(tag.lower(), SessionCopier) + removed = [] + for flag in sorted(list(local_subject_folder.rglob(f'_ibl_experiment.description_{tag}.yaml')), reverse=True): + session_path = flag.parent + days_elapsed = (datetime.datetime.now() - datetime.datetime.strptime(session_path.parts[-2], '%Y-%m-%d')).days + if days_elapsed < (weeks * 7): + continue + if copier == SessionCopier: + sc = copier(session_path, remote_subjects_folder=remote_subject_folder, tag=tag) + else: + sc = copier(session_path, remote_subjects_folder=remote_subject_folder) + if sc.state == 3: + session_size = sum(f.stat().st_size for f in session_path.rglob('*') if f.is_file()) / 1024**3 + logger.info(f'{sc.session_path}, {session_size:0.02f} Go') + size += session_size + if not dry: + shutil.rmtree(session_path) + removed.append(session_path) + logger.info(f'Cleanup size {size:0.02f} Go') + return removed
+ + + +
+[docs] +def view_session(): + """ + Entry point for command line: usage as below + >>> view_session /full/path/to/jsonable/_iblrig_taskData.raw.jsonable + :return: None + """ + from iblutil.util import setup_logger + + setup_logger('iblrig', level='INFO') + parser = argparse.ArgumentParser() + parser.add_argument('file_jsonable', help='full file path to jsonable file') + parser.add_argument('file_settings', help='full file path to settings file', nargs='?', default=None) + args = parser.parse_args() + + online_plots = OnlinePlots(settings_file=args.file_settings) + online_plots.run(file_jsonable=args.file_jsonable)
+ + + +
+[docs] +def flush(): + """Flush the valve until the user hits enter.""" + file_settings = Path(iblrig.__file__).parents[1].joinpath('settings', 'hardware_settings.yaml') + hardware_settings = yaml.safe_load(file_settings.read_text()) + bpod = Bpod(hardware_settings['device_bpod']['COM_BPOD']) + bpod.flush() + bpod.close()
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/ephys.html b/_modules/iblrig/ephys.html new file mode 100644 index 000000000..c630375e5 --- /dev/null +++ b/_modules/iblrig/ephys.html @@ -0,0 +1,221 @@ + + + + + + iblrig.ephys — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.ephys

+import argparse
+import string
+
+import numpy as np
+
+from iblatlas import atlas
+from iblrig.base_tasks import EmptySession
+from iblrig.transfer_experiments import EphysCopier
+from iblutil.util import setup_logger
+
+
+
+[docs] +def prepare_ephys_session_cmd(): + parser = argparse.ArgumentParser(prog='start_video_session', description='Prepare video PC for video recording session.') + parser.add_argument('subject_name', help='name of subject') + parser.add_argument('nprobes', help='number of probes', type=int, default=2) + parser.add_argument('--debug', action='store_true', help='enable debugging mode') + args = parser.parse_args() + setup_logger(name='iblrig', level='DEBUG' if args.debug else 'INFO') + prepare_ephys_session(args.subject_name, args.nprobes)
+ + + +
+[docs] +def prepare_ephys_session(subject_name: str, nprobes: int = 2): + """ + Setup electrophysiology recordings. + + Parameters + ---------- + subject_name : str + A subject name. + nprobes : int + Number of probes to be used + """ + # Initialize a session for paths and settings + session = EmptySession(subject=subject_name, interactive=False) + session_path = session.paths.SESSION_FOLDER + copier = EphysCopier(session_path=session_path, remote_subjects_folder=session.paths.REMOTE_SUBJECT_FOLDER) + copier.initialize_experiment(nprobes=nprobes)
+ + + +
+[docs] +def neuropixel24_micromanipulator_coordinates(ref_shank, pname, ba=None, shank_spacings_um=(0, 200, 400, 600)): + """ + Provide the micro-manipulator coordinates of the first shank. + + This function returns the relative coordinates of all shanks, labeled as probe01a, probe01b, etc. + + :param ref_shank: dictionary with keys x, y, z, phi, theta, depth, roll + example: {'x': 2594.2, 'y': -3123.7, 'z': -711, 'phi': 0 + 15, 'theta': 15, 'depth': 1250.4, 'roll': 0} + :param pname: str + :param ba: brain atlas object + :param shank_spacings_um: list of shank spacings in micrometers + :return: + """ + # this only works if the roll is 0, ie. the probe is facing upwards + assert ref_shank['roll'] == 0 + ba = atlas.NeedlesAtlas() if ba is None else ba + trajectories = {} + for i, d in enumerate(shank_spacings_um): + x = ref_shank['x'] + np.sin(ref_shank['phi'] / 180 * np.pi) * d + y = ref_shank['y'] - np.cos(ref_shank['phi'] / 180 * np.pi) * d + shank = { + 'x': x, + 'y': y, + 'z': np.NaN, + 'phi': ref_shank['phi'], + 'theta': ref_shank['theta'], + 'depth': ref_shank['depth'], + 'roll': 0, + } + insertion = atlas.Insertion.from_dict(shank, brain_atlas=ba) + xyz_entry = atlas.Insertion.get_brain_entry(insertion.trajectory, ba) + if i == 0: + xyz_ref = xyz_entry + shank['z'] = xyz_entry[2] * 1e6 + shank['depth'] = ref_shank['depth'] + (xyz_entry[2] - xyz_ref[2]) * 1e6 + trajectories[f'{pname}{string.ascii_lowercase[i]}'] = shank + return trajectories
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/frame2ttl.html b/_modules/iblrig/frame2ttl.html new file mode 100644 index 000000000..46c439080 --- /dev/null +++ b/_modules/iblrig/frame2ttl.html @@ -0,0 +1,342 @@ + + + + + + iblrig.frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.frame2ttl

+import logging
+import struct
+import time
+from typing import Literal
+
+import numpy as np
+from serial.serialutil import SerialTimeoutException
+from serial.tools.list_ports import comports
+
+from iblrig.serial_singleton import SerialSingleton
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class Frame2TTL(SerialSingleton): + _threshold_dark: int | None = None + _threshold_light: int | None = None + _calibration_stage: int = 0 + _calibrate_light: int | None = None + +
+[docs] + def __init__(self, port: str, threshold_light: int | None = None, threshold_dark: int | None = None, **kwargs) -> None: + # identify micro-controller + port_info = next((p for p in comports() if p.device == port), None) + if port_info is not None: + is_samd21mini = port_info.vid == 0x1B4F and port_info.pid in [0x8D21, 0x0D21] + is_teensy = port_info.vid == 0x16C0 and port_info.pid == 0x0483 + if not is_samd21mini and not is_teensy: + raise OSError(f'Device on {port} is not a Frame2TTL') + else: + raise OSError(f"Couldn't initialize Frame2TTL on port `{port}` - port not found.") + + # catch SAMD21 in bootloader mode (Frame2TTL v1) + if is_samd21mini and port_info.pid == 0x0D21: + raise OSError( + f'SAMD21 Mini Breakout on {port} is in bootloader mode. ' f'Replugging the device should alleviate the issue.' + ) + + # override default arguments of super-class + kwargs['baudrate'] = 115200 + kwargs['timeout'] = 0.5 + kwargs['write_timeout'] = 0.5 + + # initialize super class + super().__init__(port=port, **kwargs) + + # try to connect and identify Frame2TTL + try: + self.handshake(raise_on_fail=True) + except SerialTimeoutException as e: + if is_samd21mini: + # touch frame2ttl with magic baud rate to trigger a reboot + log.info(f'Trying to reboot frame2ttl on {self.portstr} ...') + self.baudrate = 300 + self.close() + time.sleep(1) + + # try a second handshake + self.baudrate = kwargs['baudrate'] + self.open() + try: + self.handshake(raise_on_fail=True) + except SerialTimeoutException as e: + raise OSError( + f'Writing to {self.portstr} timed out. This is a known ' + f'problem with the SAMD21 mini breakout used by ' + f'Frame2TTL v1. Updating the Frame2TTL firmware should ' + f'alleviate the issue. Alternatively, unplugging and ' + f'replugging the device should help as well.' + ) from e + else: + raise e + + # get hardware version + if is_samd21mini: + self.hw_version = 1 + else: + self.hw_version = self.query(query='#', data_specifier='B')[0] + + # get firmware version + try: + self.fw_version = self.query(query='F', data_specifier='B')[0] + except struct.error: + self.fw_version = 1 + + # set baud-rates + if self.hw_version == 3 and self.fw_version == 3: + self.baudrate = 480000000 + + # increase timeout + self.timeout = 5 + + # log status + log.debug(f'Connected to Frame2TTL v{self.hw_version} on port {self.portstr}. ' f'Firmware Version: {self.fw_version}.') + + # initialize members + match self.hw_version: + case 1: + self.unit_str = 'μs' + self._dtype_streaming = np.uint32 + case _: + self.unit_str = 'bits/ms' + self._dtype_streaming = np.uint16 + if threshold_dark is None: + threshold_dark = -150 if self.hw_version > 1 else 40 + if threshold_light is None: + threshold_light = 100 if self.hw_version > 1 else 80 + self.set_thresholds(light=threshold_light, dark=threshold_dark) + self._is_streaming = False
+ + + @property + def streaming(self) -> bool: + return self._is_streaming + + @streaming.setter + def streaming(self, state: bool): + self.write_packed('<c?', b'S', state) + self.reset_input_buffer() + self._is_streaming = state + + @property + def threshold_dark(self) -> int: + return self._threshold_dark + + @threshold_dark.setter + def threshold_dark(self, value: int) -> None: + self.set_thresholds(dark=value, light=self._threshold_light) + + @property + def threshold_light(self) -> int: + return self._threshold_light + + @threshold_light.setter + def threshold_light(self, value: int) -> None: + self.set_thresholds(dark=self._threshold_dark, light=value) + +
+[docs] + def set_thresholds(self, light: int, dark: int): + self._threshold_dark = dark + self._threshold_light = light + self.write_packed('<cHH' if self.hw_version == 1 else '<chh', b'T', self._threshold_light, self._threshold_dark) + log.debug(f'Thresholds set to {self._threshold_light} (light) and {self._threshold_dark} (dark)')
+ + +
+[docs] + def handshake(self, raise_on_fail: bool = False) -> bool: + self.flushInput() + status = self.query(query='C', data_specifier='B')[0] == 218 + if not status and raise_on_fail: + raise OSError(f'Device on {self.portstr} is not a Frame2TTL') + return status
+ + +
+[docs] + def sample(self, n_samples: int) -> np.ndarray: + buffer = bytearray(n_samples * self._dtype_streaming().itemsize) + original_timeout = self.timeout + self.timeout = None + self.streaming = True + self.readinto(buffer) + self.streaming = False + self.timeout = original_timeout + return np.frombuffer(buffer, dtype=self._dtype_streaming)
+ + +
+[docs] + def calibrate(self, condition: Literal['light', 'dark'], n_samples: int = 1000) -> tuple[int, bool]: + assert condition in ['light', 'dark'], "stage must be 'light' or 'dark'" + success = True + log.debug(f'Calibrating for {condition} condition ...') + + if self.hw_version == 1: + # TODO: taken from old routine - verify if this makes sense + values = self.sample(n_samples=n_samples) + if condition == 'light': + value = int(np.ceil(np.max(values))) + self._calibrate_light = value + else: + if self._calibrate_light is None: + raise ValueError('light threshold needs to be calibrated first') + value = int(np.floor(np.min(values))) + if value > self._calibrate_light + 40: + value = self._calibrate_light + 40 + else: + value = round(self._calibrate_light + (value - self._calibrate_light) / 3) + if value < self._calibrate_light + 5: + success = False + self._calibrate_light = None + else: + value = self.query(query='L' if condition == 'light' else 'D', data_specifier='<h')[0] + # TODO: check if readings are sufficiently different + + log.debug(f'Suggested value for {condition} threshold: {value}{self.unit_str}') + if not success: + log.error('Calibration failed. Verify that sensor is placed correctly.') + return value, success
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/graphic.html b/_modules/iblrig/graphic.html new file mode 100644 index 000000000..0df3978a1 --- /dev/null +++ b/_modules/iblrig/graphic.html @@ -0,0 +1,155 @@ + + + + + + iblrig.graphic — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.graphic

+"""Popup and string input prompts"""
+
+import tkinter as tk
+from tkinter import simpledialog
+
+
+
+[docs] +def numinput(title, prompt, default=None, minval=None, maxval=None, nullable=False, askint=False): + root = tk.Tk() + root.withdraw() + ask = simpledialog.askinteger if askint else simpledialog.askfloat + ans = ask(title, prompt, initialvalue=default, minvalue=minval, maxvalue=maxval) + if ans == 0: + return ans + elif not ans and not nullable: + return numinput(title, prompt, default=default, minval=minval, maxval=maxval, nullable=nullable, askint=askint) + return ans
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/frame2ttl.html b/_modules/iblrig/gui/frame2ttl.html new file mode 100644 index 000000000..824b79d13 --- /dev/null +++ b/_modules/iblrig/gui/frame2ttl.html @@ -0,0 +1,293 @@ + + + + + + iblrig.gui.frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.frame2ttl

+import logging
+from datetime import date
+
+from PyQt5 import QtCore, QtGui, QtTest, QtWidgets
+from PyQt5.QtWidgets import QWidget
+
+from iblrig.frame2ttl import Frame2TTL
+from iblrig.gui.tools import Worker
+from iblrig.gui.ui_frame2ttl import Ui_frame2ttl
+from iblrig.path_helper import save_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class Frame2TTLCalibrationDialog(QtWidgets.QDialog, Ui_frame2ttl): +
+[docs] + def __init__(self, *args, hardware_settings: HardwareSettings, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.setupUi(self) + self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) + self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint) + self.setWindowModality(QtCore.Qt.WindowModality.ApplicationModal) + + self.hardware_settings = hardware_settings + self.frame2ttl = Frame2TTL(port=hardware_settings.device_frame2ttl.COM_F2TTL) + self.target = Frame2TTLCalibrationTarget(self, color=QtGui.QColorConstants.White) + self.light = None + self.dark = None + self._success = True + + self.uiLabelPortValue.setText(self.frame2ttl.portstr) + self.uiLabelHardwareValue.setText(str(self.frame2ttl.hw_version)) + self.uiLabelFirmwareValue.setText(str(self.frame2ttl.fw_version)) + self.buttonBox.buttons()[0].setEnabled(False) + self.show() + + # start worker for first calibration step: light condition + worker = Worker(self.frame2ttl.calibrate, condition='light') + worker.signals.result.connect(self._on_calibrate_light_result) + QtCore.QThreadPool.globalInstance().tryStart(worker) + self.uiLabelLightValue.setText('calibrating ...')
+ + + def _on_calibrate_light_result(self, result: tuple[int, bool]): + (self.light, self._success) = result + self.uiLabelLightValue.setText(f'{self.light} {self.frame2ttl.unit_str}') + + # start worker for second calibration step: dark condition + self.target.color = QtGui.QColorConstants.Black + worker = Worker(self.frame2ttl.calibrate, condition='dark') + worker.signals.result.connect(self._on_calibrate_dark_result) + QtCore.QThreadPool.globalInstance().tryStart(worker) + self.uiLabelDarkValue.setText('calibrating ...') + + def _on_calibrate_dark_result(self, result: tuple[int, bool]): + (self.dark, self._success) = result + self.uiLabelDarkValue.setText(f'{self.dark} {self.frame2ttl.unit_str}') + + if self._success: + self.frame2ttl.set_thresholds(light=self.light, dark=self.dark) + self.hardware_settings.device_frame2ttl.F2TTL_DARK_THRESH = self.dark + self.hardware_settings.device_frame2ttl.F2TTL_LIGHT_THRESH = self.light + self.hardware_settings.device_frame2ttl.F2TTL_CALIBRATION_DATE = date.today() + save_pydantic_yaml(self.hardware_settings) + self.uiLabelResult.setText('Calibration successful.\nSettings have been updated.') + else: + self.uiLabelResult.setText('Calibration failed.\nVerify that sensor is placed correctly.') + self.buttonBox.buttons()[0].setEnabled(True) + self.frame2ttl.close()
+ + + +
+[docs] +class Frame2TTLCalibrationTarget(QtWidgets.QDialog): +
+[docs] + def __init__( + self, + parent: QWidget | None = None, + color: QtGui.QColor = QtGui.QColorConstants.White, + screen_index: int | None = None, + width: int | None = None, + height: int | None = None, + rel_pos_x: float = 1.33, + rel_pos_y: float = -1.03, + rel_extent_x: float = 0.2, + rel_extent_y: float = 0.2, + **kwargs, + ): + # try to detect screen_index, get screen dimensions + if screen_index is None: + for idx, screen in enumerate(QtWidgets.QApplication.screens()): + screen_index = idx + if screen.size().width() == 2048 and screen.size().height() == 1536: + break + else: # if no break statement occurred, i.e. no iPad screen was found + screen_index = 0 + screen = QtWidgets.QApplication.screens()[0] + log.warning( + f'Could not identify iPad screen (2048x1536) - defaulting to Screen {screen_index} ' + f'({screen.geometry().width()}x{screen.geometry().height()}).' + ) + + # convert relative parameters (used in bonsai scripts) to width and height + if width is None or height is None: + screen_width = screen.geometry().width() + screen_height = screen.geometry().height() + aspect_ratio = round(screen_width / screen_height, 2) + + # the default relative parameters are meant for 4:3 screens and need to be adapted for other aspect ratios + if rel_pos_x == 1.33 and aspect_ratio != rel_pos_x: + log.warning( + f'Screen {screen_index} has an unexpected aspect ratio of {aspect_ratio:0.2f}:1 - ' + f'setting rel_pos_x to {aspect_ratio} instead of {rel_pos_x} accordingly.' + ) + rel_pos_x = aspect_ratio + + width = round(screen_width - (screen_width + (rel_pos_x - rel_extent_x / 2) * screen_height) / 2) + height = round(screen_height - (1 - rel_pos_y - rel_extent_y / 2) * screen_height / 2) + + # display frameless QDialog with given color + super().__init__(parent, **kwargs) + self.setWindowModality(QtCore.Qt.WindowModality.NonModal) + self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.Dialog) + self.setAutoFillBackground(True) + self._set_color(color) + self.setFixedSize(width, height) + screen_geometry = QtWidgets.QApplication.desktop().screenGeometry(screen_index) + self.move( + QtCore.QPoint( + screen_geometry.x() + screen_geometry.width() - width, screen_geometry.y() + screen_geometry.height() - height + ) + ) + self.show() + QtTest.QTest.qWait(500)
+ + + def _set_color(self, color: QtGui.QColor): + palette = QtGui.QPalette() + palette.setColor(QtGui.QPalette.Window, color) + self.setPalette(palette) + + @property + def color(self) -> QtGui.QColor: + return self.palette().color(QtGui.QPalette.Window) + + @color.setter + def color(self, color: QtGui.QColor): + self._set_color(color) + self.update() + QtTest.QTest.qWait(500)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/resources_rc.html b/_modules/iblrig/gui/resources_rc.html new file mode 100644 index 000000000..f7179eb78 --- /dev/null +++ b/_modules/iblrig/gui/resources_rc.html @@ -0,0 +1,4148 @@ + + + + + + iblrig.gui.resources_rc — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.resources_rc

+# -*- coding: utf-8 -*-
+
+# Resource object code
+#
+# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2)
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt5 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x12\x68\
+\x00\
+\x01\x00\x00\x00\x0e\x00\x80\x00\x03\x00\x60\x4f\x53\x2f\x32\x09\
+\xb3\x06\xe5\x00\x00\x07\xb0\x00\x00\x00\x56\x63\x6d\x61\x70\x65\
+\xb8\xa2\x21\x00\x00\x03\x3c\x00\x00\x04\x72\x63\x76\x74\x20\x03\
+\x29\x00\x43\x00\x00\x11\x98\x00\x00\x00\x18\x66\x70\x67\x6d\xd7\
+\xc6\xe1\x2a\x00\x00\x11\xb0\x00\x00\x00\x22\x67\x6c\x79\x66\x51\
+\xbb\x68\x60\x00\x00\x08\xc8\x00\x00\x08\xd0\x68\x65\x61\x64\x25\
+\x39\xcc\x2a\x00\x00\x00\xec\x00\x00\x00\x36\x68\x68\x65\x61\x03\
+\x80\x05\x23\x00\x00\x02\x8c\x00\x00\x00\x24\x68\x6d\x74\x78\x0a\
+\x50\x0a\x1a\x00\x00\x02\xb0\x00\x00\x00\x8c\x6b\x65\x72\x6e\x00\
+\x09\x00\x90\x00\x00\x08\x08\x00\x00\x00\x18\x6c\x6f\x63\x61\x4f\
+\xb2\x4d\x90\x00\x00\x08\x40\x00\x00\x00\x86\x6d\x61\x78\x70\x00\
+\x60\x00\x41\x00\x00\x08\x20\x00\x00\x00\x20\x6e\x61\x6d\x65\x18\
+\x28\x3c\xe9\x00\x00\x01\x24\x00\x00\x01\x68\x70\x6f\x73\x74\xff\
+\xc3\x00\x20\x00\x00\x12\x48\x00\x00\x00\x20\x70\x72\x65\x70\x8b\
+\x36\x01\x25\x00\x00\x11\xd4\x00\x00\x00\x73\x00\x01\x00\x00\x00\
+\x01\x00\x00\x7b\x1a\xb7\xb1\x5f\x0f\x3c\xf5\x20\x03\x04\x00\x00\
+\x00\x00\x00\xc6\x43\x84\x80\x00\x00\x00\x00\xde\x1f\x03\xdd\xff\
+\xdd\xff\xd0\x01\xe3\x03\x00\x00\x00\x00\x08\x00\x02\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x0a\x00\x7e\x00\x03\x00\x01\x04\x09\x00\
+\x01\x00\x12\x00\x00\x00\x03\x00\x01\x04\x09\x00\x02\x00\x0e\x00\
+\x12\x00\x03\x00\x01\x04\x09\x00\x03\x00\x12\x00\x20\x00\x03\x00\
+\x01\x04\x09\x00\x04\x00\x12\x00\x32\x00\x03\x00\x01\x04\x09\x00\
+\x05\x00\x16\x00\x44\x00\x03\x00\x01\x04\x09\x00\x06\x00\x10\x00\
+\x5a\x00\x03\x00\x01\x04\x09\x00\x09\x00\x1a\x00\x6a\x00\x03\x00\
+\x01\x04\x09\x00\x0c\x00\x36\x00\x84\x00\x03\x00\x01\x04\x09\x00\
+\x0d\x00\x0e\x00\xba\x00\x03\x00\x01\x04\x09\x00\x13\x00\x22\x00\
+\xc8\x00\x37\x00\x2d\x00\x53\x00\x65\x00\x67\x00\x6d\x00\x65\x00\
+\x6e\x00\x74\x00\x52\x00\x65\x00\x67\x00\x75\x00\x6c\x00\x61\x00\
+\x72\x00\x37\x00\x2d\x00\x53\x00\x65\x00\x67\x00\x6d\x00\x65\x00\
+\x6e\x00\x74\x00\x37\x00\x2d\x00\x53\x00\x65\x00\x67\x00\x6d\x00\
+\x65\x00\x6e\x00\x74\x00\x56\x00\x65\x00\x72\x00\x73\x00\x69\x00\
+\x6f\x00\x6e\x00\x20\x00\x33\x00\x2e\x00\x30\x00\x53\x00\x65\x00\
+\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x37\x00\x4a\x00\x61\x00\
+\x6e\x00\x20\x00\x42\x00\x6f\x00\x62\x00\x72\x00\x6f\x00\x77\x00\
+\x73\x00\x6b\x00\x69\x00\x68\x00\x74\x00\x74\x00\x70\x00\x3a\x00\
+\x2f\x00\x2f\x00\x74\x00\x6f\x00\x72\x00\x69\x00\x6e\x00\x61\x00\
+\x6b\x00\x2e\x00\x63\x00\x6f\x00\x6d\x00\x2f\x00\x37\x00\x73\x00\
+\x65\x00\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\x00\x53\x00\x49\x00\
+\x4c\x00\x20\x00\x4f\x00\x46\x00\x4c\x00\x30\x00\x2e\x00\x31\x00\
+\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\
+\x20\x00\x31\x00\x32\x00\x3a\x00\x33\x00\x34\x00\x01\x00\x00\x03\
+\x60\xff\x40\x00\x00\x01\xe0\xff\xdd\xff\xff\x00\x00\x04\x00\x00\
+\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\
+\x00\x00\x00\x00\xb4\x00\x31\x00\x00\xff\xdd\x01\xe0\x00\x7b\x01\
+\x71\x01\x5c\x00\x4e\x00\x2d\x00\x44\x00\x70\x00\x2d\x01\x5c\x00\
+\x2d\x00\x4e\x00\x44\x00\x44\x00\x2d\x00\x7b\x00\x2d\x00\x44\x00\
+\x2d\x00\x2d\x00\x2d\x00\x2d\x00\x2d\x00\x2d\x00\x2d\x00\x2d\x00\
+\x2d\x00\x2d\x00\x2d\x00\x2d\x00\x44\x00\x2d\x00\x2d\x00\x44\x00\
+\x2d\x00\x4e\x00\x44\x00\x2d\x00\x2d\x00\x2d\x00\x2d\x00\x2d\x00\
+\x2d\x00\x4e\x00\x2d\x00\x2d\x00\x2d\x00\x44\x00\x2d\x00\x44\x00\
+\x2d\x00\x2d\x00\x4e\x00\x4e\x00\x2d\x00\x2d\x00\x44\x00\x44\x00\
+\x44\x00\x7b\x00\x4e\x00\x2d\x00\x44\x00\x00\x00\x00\x00\x02\x00\
+\x03\x00\x01\x00\x00\x00\x14\x00\x03\x00\x0a\x00\x00\x01\x9e\x00\
+\x04\x01\x8a\x00\x00\x00\x12\x00\x10\x00\x03\x00\x02\x00\xb0\x20\
+\x15\x20\x33\x20\x3e\x22\x12\x22\x61\x23\x1f\xf0\x67\xff\xff\x00\
+\x00\x00\x20\x20\x10\x20\x32\x20\x3e\x22\x12\x22\x61\x23\x1c\xf0\
+\x61\xff\xff\x00\x00\x00\x00\x00\x00\xdf\xc5\xdd\xf7\xdd\xc4\xdd\
+\x20\x0f\xa2\x00\x01\x00\x12\x01\x32\x01\x3c\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x41\x00\x00\x00\x3a\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x08\x00\x15\x00\x37\x00\x00\x00\x00\x00\
+\x05\x00\x09\x00\x02\x00\x00\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\
+\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x01\x00\x00\x00\
+\x00\x00\x36\x00\x00\x00\x38\x00\x00\x00\x14\x00\x12\x00\x15\x00\
+\x0a\x00\x16\x00\x17\x00\x18\x00\x19\x00\x0b\x00\x1a\x00\x1b\x00\
+\x1c\x00\x1d\x00\x1e\x00\x0a\x00\x1f\x00\x20\x00\x21\x00\x0f\x00\
+\x11\x00\x22\x00\x23\x00\x24\x00\x25\x00\x26\x00\x0c\x00\x15\x00\
+\x00\x00\x37\x00\x00\x00\x06\x00\x08\x00\x27\x00\x28\x00\x29\x00\
+\x2a\x00\x2b\x00\x17\x00\x13\x00\x2c\x00\x05\x00\x2d\x00\x2e\x00\
+\x1c\x00\x1d\x00\x2f\x00\x30\x00\x1f\x00\x31\x00\x32\x00\x33\x00\
+\x34\x00\x35\x00\x23\x00\x24\x00\x25\x00\x26\x00\x0c\x00\x00\x00\
+\x39\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x3b\x00\x09\x00\x09\x00\x09\x00\
+\x09\x00\x09\x00\x09\x00\x08\x00\x3a\x00\x0c\x00\x00\x00\x00\x02\
+\xd4\x00\x00\x00\x00\x00\x00\x00\x3b\x00\x00\x00\x20\x00\x00\x00\
+\x20\x00\x00\x00\x41\x00\x00\x00\x22\x00\x00\x00\x22\x00\x00\x00\
+\x3a\x00\x00\x00\x27\x00\x00\x00\x27\x00\x00\x00\x08\x00\x00\x00\
+\x28\x00\x00\x00\x28\x00\x00\x00\x15\x00\x00\x00\x29\x00\x00\x00\
+\x29\x00\x00\x00\x37\x00\x00\x00\x2c\x00\x00\x00\x2c\x00\x00\x00\
+\x05\x00\x00\x00\x2d\x00\x00\x00\x2d\x00\x00\x00\x09\x00\x00\x00\
+\x2e\x00\x00\x00\x2e\x00\x00\x00\x02\x00\x00\x00\x30\x00\x00\x00\
+\x39\x00\x00\x00\x0a\x00\x00\x00\x3a\x00\x00\x00\x3a\x00\x00\x00\
+\x01\x00\x00\x00\x3d\x00\x00\x00\x3d\x00\x00\x00\x36\x00\x00\x00\
+\x3f\x00\x00\x00\x3f\x00\x00\x00\x38\x00\x00\x00\x41\x00\x00\x00\
+\x41\x00\x00\x00\x14\x00\x00\x00\x42\x00\x00\x00\x42\x00\x00\x00\
+\x12\x00\x00\x00\x43\x00\x00\x00\x43\x00\x00\x00\x15\x00\x00\x00\
+\x44\x00\x00\x00\x44\x00\x00\x00\x0a\x00\x00\x00\x45\x00\x00\x00\
+\x48\x00\x00\x00\x16\x00\x00\x00\x49\x00\x00\x00\x49\x00\x00\x00\
+\x0b\x00\x00\x00\x4a\x00\x00\x00\x4e\x00\x00\x00\x1a\x00\x00\x00\
+\x4f\x00\x00\x00\x4f\x00\x00\x00\x0a\x00\x00\x00\x50\x00\x00\x00\
+\x52\x00\x00\x00\x1f\x00\x00\x00\x53\x00\x00\x00\x53\x00\x00\x00\
+\x0f\x00\x00\x00\x54\x00\x00\x00\x54\x00\x00\x00\x11\x00\x00\x00\
+\x55\x00\x00\x00\x59\x00\x00\x00\x22\x00\x00\x00\x5a\x00\x00\x00\
+\x5a\x00\x00\x00\x0c\x00\x00\x00\x5b\x00\x00\x00\x5b\x00\x00\x00\
+\x15\x00\x00\x00\x5d\x00\x00\x00\x5d\x00\x00\x00\x37\x00\x00\x00\
+\x5f\x00\x00\x00\x5f\x00\x00\x00\x06\x00\x00\x00\x60\x00\x00\x00\
+\x60\x00\x00\x00\x08\x00\x00\x00\x61\x00\x00\x00\x65\x00\x00\x00\
+\x27\x00\x00\x00\x66\x00\x00\x00\x66\x00\x00\x00\x17\x00\x00\x00\
+\x67\x00\x00\x00\x67\x00\x00\x00\x13\x00\x00\x00\x68\x00\x00\x00\
+\x68\x00\x00\x00\x2c\x00\x00\x00\x69\x00\x00\x00\x69\x00\x00\x00\
+\x05\x00\x00\x00\x6a\x00\x00\x00\x6b\x00\x00\x00\x2d\x00\x00\x00\
+\x6c\x00\x00\x00\x6d\x00\x00\x00\x1c\x00\x00\x00\x6e\x00\x00\x00\
+\x6f\x00\x00\x00\x2f\x00\x00\x00\x70\x00\x00\x00\x70\x00\x00\x00\
+\x1f\x00\x00\x00\x71\x00\x00\x00\x75\x00\x00\x00\x31\x00\x00\x00\
+\x76\x00\x00\x00\x79\x00\x00\x00\x23\x00\x00\x00\x7a\x00\x00\x00\
+\x7a\x00\x00\x00\x0c\x00\x00\x00\x7c\x00\x00\x00\x7c\x00\x00\x00\
+\x39\x00\x00\x00\xb0\x00\x00\x00\xb0\x00\x00\x00\x3b\x00\x00\x20\
+\x10\x00\x00\x20\x10\x00\x00\x00\x09\x00\x00\x20\x11\x00\x00\x20\
+\x11\x00\x00\x00\x09\x00\x00\x20\x12\x00\x00\x20\x12\x00\x00\x00\
+\x09\x00\x00\x20\x13\x00\x00\x20\x13\x00\x00\x00\x09\x00\x00\x20\
+\x14\x00\x00\x20\x14\x00\x00\x00\x09\x00\x00\x20\x15\x00\x00\x20\
+\x15\x00\x00\x00\x09\x00\x00\x20\x32\x00\x00\x20\x32\x00\x00\x00\
+\x08\x00\x00\x20\x33\x00\x00\x20\x33\x00\x00\x00\x3a\x00\x00\x20\
+\x3e\x00\x00\x20\x3e\x00\x00\x00\x03\x00\x00\x22\x12\x00\x00\x22\
+\x12\x00\x00\x00\x09\x00\x00\x22\x61\x00\x00\x22\x61\x00\x00\x00\
+\x25\x00\x00\x23\x1c\x00\x00\x23\x1f\x00\x00\x00\x3c\x00\x00\xf0\
+\x61\x00\x00\xf0\x67\x00\x00\x00\x03\x00\x01\xfb\xf0\x00\x01\xfb\
+\xf6\x00\x00\x00\x0a\x00\x01\xfb\xf7\x00\x01\xfb\xf7\x00\x00\x00\
+\x40\x00\x01\xfb\xf8\x00\x01\xfb\xf9\x00\x00\x00\x12\x00\x00\x00\
+\x01\x00\x00\x01\x90\x00\x05\x00\x00\x02\x00\x02\x00\x00\x00\xfe\
+\x00\x02\x00\x02\x00\x00\x00\x02\x00\x00\x01\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\
+\x00\xff\xff\x03\x60\xff\x40\x00\x00\x03\x60\x00\xc0\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x14\x00\
+\x01\x00\x01\x00\x06\x00\x00\x00\x00\x00\x02\x00\x02\x00\x78\x00\
+\x01\x00\x00\x00\x42\x00\x08\x00\x02\x00\x30\x00\x07\x00\x00\x00\
+\x00\x00\x01\x00\x03\x00\x00\x00\x0a\x00\x07\x00\x07\x00\x01\x00\
+\x00\x00\x00\x00\x14\x00\x21\x00\x35\x00\x4b\x00\x61\x00\x74\x00\
+\x89\x00\x9f\x00\xb2\x00\xc9\x00\xd4\x00\xe8\x00\xfc\x01\x0d\x01\
+\x21\x01\x38\x01\x46\x01\x60\x01\x77\x01\x8e\x01\x9f\x01\xb3\x01\
+\xc4\x01\xd8\x01\xec\x01\xfd\x02\x11\x02\x1f\x02\x30\x02\x44\x02\
+\x58\x02\x6c\x02\x7a\x02\x8e\x02\x9c\x02\xb3\x02\xc1\x02\xd5\x02\
+\xec\x03\x00\x03\x0e\x03\x22\x03\x39\x03\x4a\x03\x58\x03\x6c\x03\
+\x7a\x03\x8b\x03\x9f\x03\xaa\x03\xb8\x03\xc9\x03\xd7\x03\xe2\x03\
+\xf3\x04\x04\x04\x0f\x04\x1a\x04\x2b\x04\x36\x04\x41\x04\x4c\x04\
+\x57\x04\x68\x04\x68\x00\x00\x00\x02\x00\x31\x00\xa8\x00\xac\x02\
+\x58\x00\x03\x00\x07\x00\x00\x3f\x01\x33\x07\x03\x37\x33\x07\x31\
+\x06\x60\x06\x4b\x06\x60\x06\xa8\x60\x60\x01\x50\x60\x60\x00\x00\
+\x01\xff\xdd\xff\xd0\x00\x23\x00\x30\x00\x03\x00\x00\x07\x37\x33\
+\x07\x23\x06\x40\x06\x30\x60\x60\x00\x00\x01\x00\x7b\x02\xa0\x01\
+\x99\x03\x00\x00\x06\x00\x06\xb3\x04\x01\x05\x01\x2b\x01\x23\x27\
+\x36\x3b\x01\x17\x01\x71\xb0\x46\x1c\x23\xcc\x13\x02\xa0\x4a\x16\
+\x02\x00\x01\x01\x71\x01\x8d\x01\xe3\x02\xf8\x00\x06\x00\x07\xb4\
+\x01\x08\x05\x06\x02\x2b\x01\x37\x16\x0f\x02\x27\x01\x7f\x2c\x38\
+\x03\x10\x22\x3d\x02\x91\x67\x19\x3f\xfa\x19\x30\x00\x00\x01\x01\
+\x5c\x00\x07\x01\xcb\x01\x72\x00\x06\x00\x07\xb4\x01\x07\x05\x09\
+\x02\x2b\x01\x37\x17\x07\x06\x07\x27\x01\x6a\x42\x1f\x0f\x04\x3c\
+\x20\x01\x42\x30\x19\xf9\x40\x19\x67\x00\x01\x00\x4e\x00\x00\x01\
+\x69\x00\x60\x00\x06\x00\x06\xb3\x01\x04\x03\x01\x2b\x37\x33\x17\
+\x07\x23\x22\x27\x9d\xb0\x1c\x13\xcc\x23\x19\x60\x5f\x01\x15\x00\
+\x01\x00\x2d\x00\x23\x00\x9e\x01\x72\x00\x06\x00\x07\xb4\x05\x07\
+\x01\x0a\x02\x2b\x37\x07\x26\x3f\x02\x17\x90\x4f\x14\x03\x0f\x22\
+\x3d\x6d\x4a\x1a\x23\xf9\x19\x30\x00\x00\x01\x00\x44\x01\x8d\x00\
+\xb3\x02\xdc\x00\x06\x00\x07\xb4\x05\x0b\x01\x06\x02\x2b\x13\x07\
+\x27\x37\x36\x37\x17\xa5\x42\x1f\x10\x02\x17\x46\x01\xbd\x30\x19\
+\xfa\x22\x1a\x4a\x00\x00\x01\x00\x70\x01\x50\x01\x9f\x01\xb0\x00\
+\x05\x00\x06\xb3\x01\x05\x04\x01\x2b\x13\x37\x33\x17\x07\x23\x70\
+\x42\xb1\x3c\x42\xb1\x01\x80\x30\x30\x30\x00\xff\xff\x00\x2d\x00\
+\x00\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\
+\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\
+\x07\x00\x00\x00\x02\x00\x08\x00\x00\xff\xff\x01\x5c\x00\x07\x01\
+\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\x02\x00\x05\x00\x00\xff\
+\xff\x00\x2d\x00\x00\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\
+\x22\x00\x04\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x4e\x00\x00\x01\xe3\x03\
+\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\
+\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x44\x00\x07\x01\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\
+\x22\x00\x05\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\
+\x00\xff\xff\x00\x44\x00\x00\x01\xcb\x03\x00\x00\x22\x00\x03\x00\
+\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\
+\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\
+\xcb\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x05\x00\x00\x00\
+\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\x08\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x7b\x00\x07\x01\xe3\x03\
+\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x02\x00\
+\x05\x00\x00\xff\xff\x00\x2d\x00\x00\x01\xe3\x03\x00\x00\x22\x00\
+\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\x00\x00\
+\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\x08\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x44\x00\x00\x01\xe3\x03\
+\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\
+\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x08\x00\x00\x00\
+\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x07\x01\xe3\x03\x00\x00\
+\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\
+\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\
+\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\x99\x03\x00\x00\x22\x00\
+\x03\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\
+\x02\x00\x08\x00\x00\xff\xff\x00\x2d\x00\x00\x01\x9f\x03\x00\x00\
+\x22\x00\x03\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\
+\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\
+\x2d\x00\x23\x01\x9f\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\
+\x07\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x2d\x00\x00\x01\xcb\x03\x00\x00\x22\x00\x03\x00\x00\x00\
+\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\
+\x00\x00\x02\x00\x08\x00\x00\xff\xff\x00\x2d\x00\x07\x01\xe3\x02\
+\xf8\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\
+\x07\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x2d\x00\x00\x01\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\
+\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x02\x00\x07\x00\
+\x00\xff\xff\x00\x2d\x00\x00\x01\xe3\x02\xf8\x00\x22\x00\x04\x00\
+\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\
+\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\
+\x69\x02\xdc\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\
+\x02\x00\x08\x00\x00\xff\xff\x00\x2d\x00\x07\x01\xcb\x03\x00\x00\
+\x22\x00\x03\x00\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\x07\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x07\x01\xe3\x03\
+\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\
+\x05\x00\x00\x00\x22\x00\x07\x00\x00\x00\x02\x00\x08\x00\x00\xff\
+\xff\x00\x2d\x00\x23\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\
+\x22\x00\x04\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\x08\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x44\x00\x00\x01\xe3\x03\
+\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\
+\x06\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x2d\x00\x23\x01\x99\x03\x00\x00\x22\x00\x03\x00\x00\x00\
+\x22\x00\x07\x00\x00\x00\x02\x00\x08\x00\x00\xff\xff\x00\x2d\x00\
+\x00\x01\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\
+\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x02\x00\
+\x08\x00\x00\xff\xff\x00\x44\x00\x00\x01\xe3\x02\xf8\x00\x22\x00\
+\x04\x00\x00\x00\x22\x00\x06\x00\x00\x00\x02\x00\x08\x00\x00\xff\
+\xff\x00\x2d\x00\x00\x01\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\
+\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\
+\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\
+\x4e\x00\x00\x01\x9f\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\
+\x06\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x44\x00\x00\x01\
+\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\x00\x00\
+\x22\x00\x06\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\
+\x00\xff\xff\x00\x2d\x00\x00\x01\xe3\x03\x00\x00\x22\x00\x03\x00\
+\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\
+\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x2d\x00\x00\x01\xcb\x02\xdc\x00\x22\x00\x05\x00\x00\x00\
+\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\x08\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\x9f\x01\
+\xb0\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x02\x00\
+\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\xe3\x02\xf8\x00\x22\x00\
+\x04\x00\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\
+\x22\x00\x07\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\
+\x00\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\
+\x00\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\
+\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x07\x01\
+\xcb\x02\xdc\x00\x22\x00\x05\x00\x00\x00\x22\x00\x07\x00\x00\x00\
+\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x4e\x00\
+\x00\x01\xe3\x02\xf8\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\
+\x00\x00\x02\x00\x06\x00\x00\xff\xff\x00\x2d\x00\x07\x01\xcb\x03\
+\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\
+\x07\x00\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x2d\x00\x07\x01\xcb\x01\xb0\x00\x22\x00\x05\x00\x00\x00\
+\x22\x00\x07\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\
+\x00\x01\xcb\x01\xb0\x00\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\
+\x00\x00\x22\x00\x07\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\
+\x44\x00\x07\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\
+\x04\x00\x00\x00\x22\x00\x05\x00\x00\x00\x22\x00\x08\x00\x00\x00\
+\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x23\x01\x9f\x01\xb0\x00\
+\x22\x00\x07\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x44\x00\
+\x07\x01\xcb\x02\xdc\x00\x22\x00\x05\x00\x00\x00\x22\x00\x08\x00\
+\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\x9f\x02\
+\xdc\x00\x22\x00\x06\x00\x00\x00\x22\x00\x07\x00\x00\x00\x22\x00\
+\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x2d\x00\x00\x01\
+\xcb\x01\x72\x00\x22\x00\x05\x00\x00\x00\x22\x00\x06\x00\x00\x00\
+\x02\x00\x07\x00\x00\xff\xff\x00\x4e\x00\x00\x01\x9f\x01\xb0\x00\
+\x22\x00\x06\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\x4e\x00\
+\x00\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\
+\x00\x00\x22\x00\x05\x00\x00\x00\x02\x00\x06\x00\x00\xff\xff\x00\
+\x2d\x00\x23\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\
+\x04\x00\x00\x00\x22\x00\x07\x00\x00\x00\x02\x00\x09\x00\x00\xff\
+\xff\x00\x2d\x00\x23\x00\xb3\x02\xdc\x00\x22\x00\x07\x00\x00\x00\
+\x02\x00\x08\x00\x00\xff\xff\x00\x44\x01\x8d\x01\xe3\x02\xf8\x00\
+\x22\x00\x04\x00\x00\x00\x02\x00\x08\x00\x00\xff\xff\x00\x44\x01\
+\x50\x01\xe3\x03\x00\x00\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\
+\x00\x00\x22\x00\x08\x00\x00\x00\x02\x00\x09\x00\x00\xff\xff\x00\
+\x44\x01\x8d\x01\x99\x03\x00\x00\x22\x00\x03\x00\x00\x00\x02\x00\
+\x08\x00\x00\xff\xff\x00\x7b\x01\x8d\x01\xe3\x03\x00\x00\x22\x00\
+\x03\x00\x00\x00\x02\x00\x04\x00\x00\xff\xff\x00\x4e\x00\x00\x01\
+\xcb\x01\x72\x00\x22\x00\x05\x00\x00\x00\x02\x00\x06\x00\x00\xff\
+\xff\x00\x2d\x00\x00\x01\x69\x01\x72\x00\x22\x00\x06\x00\x00\x00\
+\x02\x00\x07\x00\x00\xff\xff\x00\x44\x00\x07\x01\xe3\x03\x00\x00\
+\x22\x00\x03\x00\x00\x00\x22\x00\x04\x00\x00\x00\x22\x00\x05\x00\
+\x00\x00\x02\x00\x08\x00\x00\x03\x00\x00\x60\x00\x0d\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\xff\xf8\x00\x07\x00\x23\xff\xdc\xb0\
+\x00\x2c\x00\xb9\x03\xfe\x3f\xe0\x0b\x3e\x2d\xb0\x01\x2c\xb0\x00\
+\x2b\xb0\x01\xfd\x30\x31\x2d\xb0\x02\x2c\xb0\x00\x2b\x3e\x30\x31\
+\x2d\x00\x00\xb0\x01\x45\x69\x20\xb0\x01\x23\x44\x20\x20\xb0\x00\
+\x45\x23\x61\xb0\x20\x63\x69\x23\x61\x20\xb0\x00\x23\x42\xb0\x03\
+\x45\x66\x20\xb0\x03\x23\x44\x20\xb0\x09\x45\x60\xb0\x09\x23\x44\
+\x20\xb0\x0a\x45\x60\xb0\x0a\x23\x44\x60\x60\x20\xb0\x04\x23\x44\
+\x20\xb0\x01\x45\x60\x20\xb0\x00\x43\x60\x20\xb0\x05\x23\x44\xb0\
+\x01\x45\x60\x20\xb1\x08\x08\x45\x8a\x60\x44\xb1\x0b\x0b\x45\x8a\
+\x60\x44\x60\xb0\x20\x63\x20\xb0\x02\x45\x20\x8a\x60\xb0\x06\x23\
+\x44\x61\xb0\x07\x23\x44\x00\x00\x03\x00\x00\x00\x00\x00\x00\xff\
+\xc0\x00\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x03\x78\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x30\
+\x20\x32\x30\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
+\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
+\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x39\x34\
+\x20\x37\x33\x39\x39\x63\x35\x2e\x35\x32\x33\x20\x30\x20\x31\x30\
+\x20\x34\x2e\x35\x39\x20\x31\x30\x20\x31\x30\x2e\x32\x35\x33\x20\
+\x30\x20\x34\x2e\x35\x32\x39\x2d\x32\x2e\x38\x36\x32\x20\x38\x2e\
+\x33\x37\x31\x2d\x36\x2e\x38\x33\x33\x20\x39\x2e\x37\x32\x38\x2d\
+\x2e\x35\x30\x37\x2e\x31\x30\x31\x2d\x2e\x36\x38\x37\x2d\x2e\x32\
+\x31\x39\x2d\x2e\x36\x38\x37\x2d\x2e\x34\x39\x32\x20\x30\x2d\x2e\
+\x33\x33\x38\x2e\x30\x31\x32\x2d\x31\x2e\x34\x34\x32\x2e\x30\x31\
+\x32\x2d\x32\x2e\x38\x31\x34\x20\x30\x2d\x2e\x39\x35\x36\x2d\x2e\
+\x33\x32\x2d\x31\x2e\x35\x38\x2d\x2e\x36\x37\x39\x2d\x31\x2e\x38\
+\x39\x38\x20\x32\x2e\x32\x32\x37\x2d\x2e\x32\x35\x34\x20\x34\x2e\
+\x35\x36\x37\x2d\x31\x2e\x31\x32\x31\x20\x34\x2e\x35\x36\x37\x2d\
+\x35\x2e\x30\x35\x39\x20\x30\x2d\x31\x2e\x31\x32\x2d\x2e\x33\x38\
+\x38\x2d\x32\x2e\x30\x33\x34\x2d\x31\x2e\x30\x33\x2d\x32\x2e\x37\
+\x35\x32\x2e\x31\x30\x34\x2d\x2e\x32\x35\x39\x2e\x34\x34\x37\x2d\
+\x31\x2e\x33\x30\x32\x2d\x2e\x30\x39\x38\x2d\x32\x2e\x37\x31\x34\
+\x20\x30\x20\x30\x2d\x2e\x38\x33\x38\x2d\x2e\x32\x37\x35\x2d\x32\
+\x2e\x37\x34\x37\x20\x31\x2e\x30\x35\x31\x2d\x2e\x37\x39\x39\x2d\
+\x2e\x32\x32\x37\x2d\x31\x2e\x36\x35\x35\x2d\x2e\x33\x34\x31\x2d\
+\x32\x2e\x35\x30\x35\x2d\x2e\x33\x34\x35\x2d\x2e\x38\x35\x2e\x30\
+\x30\x34\x2d\x31\x2e\x37\x30\x35\x2e\x31\x31\x38\x2d\x32\x2e\x35\
+\x30\x33\x2e\x33\x34\x35\x2d\x31\x2e\x39\x31\x31\x2d\x31\x2e\x33\
+\x32\x36\x2d\x32\x2e\x37\x35\x31\x2d\x31\x2e\x30\x35\x31\x2d\x32\
+\x2e\x37\x35\x31\x2d\x31\x2e\x30\x35\x31\x2d\x2e\x35\x34\x33\x20\
+\x31\x2e\x34\x31\x32\x2d\x2e\x32\x20\x32\x2e\x34\x35\x35\x2d\x2e\
+\x30\x39\x37\x20\x32\x2e\x37\x31\x34\x2d\x2e\x36\x33\x39\x2e\x37\
+\x31\x38\x2d\x31\x2e\x30\x33\x20\x31\x2e\x36\x33\x32\x2d\x31\x2e\
+\x30\x33\x20\x32\x2e\x37\x35\x32\x20\x30\x20\x33\x2e\x39\x32\x38\
+\x20\x32\x2e\x33\x33\x35\x20\x34\x2e\x38\x30\x38\x20\x34\x2e\x35\
+\x35\x36\x20\x35\x2e\x30\x36\x37\x2d\x2e\x32\x38\x36\x2e\x32\x35\
+\x36\x2d\x2e\x35\x34\x35\x2e\x37\x30\x38\x2d\x2e\x36\x33\x35\x20\
+\x31\x2e\x33\x37\x31\x2d\x2e\x35\x37\x2e\x32\x36\x32\x2d\x32\x2e\
+\x30\x31\x38\x2e\x37\x31\x35\x2d\x32\x2e\x39\x31\x2d\x2e\x38\x35\
+\x32\x20\x30\x20\x30\x2d\x2e\x35\x32\x39\x2d\x2e\x39\x38\x35\x2d\
+\x31\x2e\x35\x33\x33\x2d\x31\x2e\x30\x35\x37\x20\x30\x20\x30\x2d\
+\x2e\x39\x37\x35\x2d\x2e\x30\x31\x33\x2d\x2e\x30\x36\x38\x2e\x36\
+\x32\x33\x20\x30\x20\x30\x20\x2e\x36\x35\x35\x2e\x33\x31\x35\x20\
+\x31\x2e\x31\x31\x20\x31\x2e\x35\x20\x30\x20\x30\x20\x2e\x35\x38\
+\x37\x20\x31\x2e\x38\x33\x20\x33\x2e\x33\x36\x39\x20\x31\x2e\x32\
+\x31\x2e\x30\x30\x35\x2e\x38\x35\x37\x2e\x30\x31\x34\x20\x31\x2e\
+\x36\x36\x35\x2e\x30\x31\x34\x20\x31\x2e\x39\x30\x39\x20\x30\x20\
+\x2e\x32\x37\x31\x2d\x2e\x31\x38\x34\x2e\x35\x38\x38\x2d\x2e\x36\
+\x38\x33\x2e\x34\x39\x33\x2d\x33\x2e\x39\x37\x34\x2d\x31\x2e\x33\
+\x35\x35\x2d\x36\x2e\x38\x33\x39\x2d\x35\x2e\x31\x39\x39\x2d\x36\
+\x2e\x38\x33\x39\x2d\x39\x2e\x37\x32\x39\x20\x30\x2d\x35\x2e\x36\
+\x36\x33\x20\x34\x2e\x34\x37\x38\x2d\x31\x30\x2e\x32\x35\x33\x20\
+\x31\x30\x2d\x31\x30\x2e\x32\x35\x33\x22\x20\x66\x69\x6c\x6c\x2d\
+\x72\x75\x6c\x65\x3d\x22\x65\x76\x65\x6e\x6f\x64\x64\x22\x20\x74\
+\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\
+\x61\x74\x65\x28\x2d\x38\x34\x20\x2d\x37\x33\x39\x39\x29\x22\x2f\
+\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x03\x49\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x31\x20\x38\x30\
+\x30\x20\x38\x30\x30\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\
+\x30\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\
+\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\
+\x2f\x73\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\
+\x38\x37\x2e\x35\x20\x35\x31\x2e\x30\x34\x37\x39\x31\x39\x68\x34\
+\x32\x35\x63\x34\x38\x2e\x33\x20\x30\x20\x38\x37\x2e\x35\x20\x33\
+\x39\x2e\x32\x20\x38\x37\x2e\x35\x20\x38\x37\x2e\x35\x30\x30\x30\
+\x30\x31\x76\x32\x37\x35\x61\x38\x37\x2e\x35\x20\x38\x37\x2e\x35\
+\x20\x30\x20\x30\x20\x31\x20\x2d\x38\x37\x2e\x35\x20\x38\x37\x2e\
+\x35\x68\x2d\x31\x35\x39\x2e\x34\x35\x6c\x2d\x31\x32\x38\x2e\x37\
+\x20\x31\x32\x38\x2e\x36\x35\x61\x37\x32\x2e\x39\x20\x37\x32\x2e\
+\x39\x20\x30\x20\x30\x20\x31\x20\x2d\x31\x32\x34\x2e\x33\x35\x2d\
+\x35\x31\x2e\x35\x76\x2d\x37\x37\x2e\x31\x35\x68\x2d\x31\x32\x2e\
+\x35\x61\x38\x37\x2e\x35\x20\x38\x37\x2e\x35\x20\x30\x20\x30\x20\
+\x31\x20\x2d\x38\x37\x2e\x35\x2d\x38\x37\x2e\x35\x76\x2d\x32\x37\
+\x35\x63\x30\x2d\x34\x38\x2e\x33\x30\x30\x30\x30\x31\x20\x33\x39\
+\x2e\x32\x2d\x38\x37\x2e\x35\x30\x30\x30\x30\x31\x20\x38\x37\x2e\
+\x35\x2d\x38\x37\x2e\x35\x30\x30\x30\x30\x31\x7a\x6d\x2d\x31\x32\
+\x2e\x35\x20\x38\x37\x2e\x35\x30\x30\x30\x30\x31\x76\x32\x37\x35\
+\x63\x30\x20\x36\x2e\x39\x20\x35\x2e\x36\x20\x31\x32\x2e\x35\x20\
+\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x68\x35\x30\x61\x33\x37\x2e\
+\x35\x20\x33\x37\x2e\x35\x20\x30\x20\x30\x20\x31\x20\x33\x37\x2e\
+\x35\x20\x33\x37\x2e\x35\x76\x31\x30\x39\x2e\x35\x6c\x31\x33\x36\
+\x2d\x31\x33\x36\x61\x33\x37\x2e\x34\x35\x20\x33\x37\x2e\x34\x35\
+\x20\x30\x20\x30\x20\x31\x20\x32\x36\x2e\x35\x2d\x31\x31\x68\x31\
+\x37\x35\x61\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x20\x30\x20\x30\
+\x20\x30\x20\x31\x32\x2e\x35\x2d\x31\x32\x2e\x35\x76\x2d\x32\x37\
+\x35\x61\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x20\x30\x20\x30\x20\
+\x30\x20\x2d\x31\x32\x2e\x35\x2d\x31\x32\x2e\x35\x68\x2d\x34\x32\
+\x35\x61\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x20\x30\x20\x30\x20\
+\x30\x20\x2d\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x7a\x6d\x36\x35\
+\x30\x20\x31\x30\x30\x61\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x20\
+\x30\x20\x30\x20\x30\x20\x2d\x31\x32\x2e\x35\x2d\x31\x32\x2e\x35\
+\x68\x2d\x32\x35\x61\x33\x37\x2e\x35\x20\x33\x37\x2e\x35\x20\x30\
+\x20\x30\x20\x31\x20\x30\x2d\x37\x35\x68\x32\x35\x63\x34\x38\x2e\
+\x33\x20\x30\x20\x38\x37\x2e\x35\x20\x33\x39\x2e\x32\x20\x38\x37\
+\x2e\x35\x20\x38\x37\x2e\x35\x76\x32\x37\x35\x61\x38\x37\x2e\x35\
+\x20\x38\x37\x2e\x35\x20\x30\x20\x30\x20\x31\x20\x2d\x38\x37\x2e\
+\x35\x20\x38\x37\x2e\x35\x68\x2d\x31\x32\x2e\x35\x76\x37\x37\x2e\
+\x31\x35\x61\x37\x32\x2e\x39\x20\x37\x32\x2e\x39\x20\x30\x20\x30\
+\x20\x31\x20\x2d\x31\x32\x34\x2e\x33\x35\x20\x35\x31\x2e\x35\x6c\
+\x2d\x31\x31\x34\x2e\x36\x35\x2d\x31\x31\x34\x2e\x36\x35\x61\x33\
+\x37\x2e\x34\x35\x20\x33\x37\x2e\x34\x35\x20\x30\x20\x30\x20\x31\
+\x20\x31\x36\x2e\x33\x2d\x36\x33\x2e\x37\x35\x20\x33\x37\x2e\x34\
+\x35\x20\x33\x37\x2e\x34\x35\x20\x30\x20\x30\x20\x31\x20\x33\x36\
+\x2e\x37\x20\x31\x30\x2e\x37\x35\x6c\x31\x31\x31\x20\x31\x31\x31\
+\x76\x2d\x31\x30\x39\x2e\x35\x61\x33\x37\x2e\x35\x20\x33\x37\x2e\
+\x35\x20\x30\x20\x30\x20\x31\x20\x33\x37\x2e\x35\x2d\x33\x37\x2e\
+\x35\x68\x35\x30\x61\x31\x32\x2e\x35\x20\x31\x32\x2e\x35\x20\x30\
+\x20\x30\x20\x30\x20\x31\x32\x2e\x35\x2d\x31\x32\x2e\x35\x7a\x22\
+\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x00\xd9\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x31\x32\
+\x20\x31\x32\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
+\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
+\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x31\
+\x36\x38\x20\x31\x32\x38\x39\x68\x2d\x31\x32\x76\x31\x32\x68\x31\
+\x32\x7a\x6d\x2d\x33\x20\x33\x68\x2d\x36\x76\x31\x68\x36\x7a\x6d\
+\x2d\x36\x20\x32\x68\x36\x76\x31\x68\x2d\x36\x7a\x6d\x36\x20\x32\
+\x68\x2d\x36\x76\x31\x68\x36\x7a\x22\x20\x66\x69\x6c\x6c\x2d\x72\
+\x75\x6c\x65\x3d\x22\x65\x76\x65\x6e\x6f\x64\x64\x22\x20\x74\x72\
+\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x74\x72\x61\x6e\x73\x6c\x61\
+\x74\x65\x28\x2d\x31\x31\x35\x36\x20\x2d\x31\x32\x38\x39\x29\x22\
+\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x03\x29\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x31\x31\x2e\x36\x37\x20\x32\x31\x31\x2e\x36\x37\x22\x20\x78\x6d\
+\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\
+\x3e\x0a\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x30\x35\
+\x2e\x38\x33\x20\x30\x61\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\
+\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x2d\x31\x30\x35\x2e\x38\x33\
+\x20\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x31\
+\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x20\x31\x30\x35\x2e\
+\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\
+\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x20\x31\x30\
+\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\
+\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x2d\
+\x31\x30\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x7a\x6d\x2d\
+\x35\x39\x2e\x33\x35\x32\x20\x38\x39\x2e\x30\x32\x39\x61\x31\x36\
+\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x34\x20\x30\x20\x30\x20\
+\x31\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x35\x20\
+\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x34\x20\x30\x20\
+\x30\x20\x31\x2d\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\
+\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x34\x20\
+\x30\x20\x30\x20\x31\x2d\x31\x36\x2e\x38\x30\x35\x2d\x31\x36\x2e\
+\x38\x30\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\
+\x34\x20\x30\x20\x30\x20\x31\x20\x31\x36\x2e\x38\x30\x35\x2d\x31\
+\x36\x2e\x38\x30\x35\x7a\x6d\x35\x39\x2e\x33\x35\x32\x20\x30\x61\
+\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x34\x20\x30\x20\
+\x30\x20\x31\x20\x31\x36\x2e\x38\x30\x35\x20\x31\x36\x2e\x38\x30\
+\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x34\x20\
+\x30\x20\x30\x20\x31\x2d\x31\x36\x2e\x38\x30\x35\x20\x31\x36\x2e\
+\x38\x30\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\
+\x34\x20\x30\x20\x30\x20\x31\x2d\x31\x36\x2e\x38\x30\x35\x2d\x31\
+\x36\x2e\x38\x30\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\
+\x38\x30\x34\x20\x30\x20\x30\x20\x31\x20\x31\x36\x2e\x38\x30\x35\
+\x2d\x31\x36\x2e\x38\x30\x35\x7a\x6d\x35\x39\x2e\x33\x35\x32\x20\
+\x30\x61\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\x34\x20\
+\x30\x20\x30\x20\x31\x20\x31\x36\x2e\x38\x30\x35\x20\x31\x36\x2e\
+\x38\x30\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\x38\x30\
+\x34\x20\x30\x20\x30\x20\x31\x2d\x31\x36\x2e\x38\x30\x35\x20\x31\
+\x36\x2e\x38\x30\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\x36\x2e\
+\x38\x30\x34\x20\x30\x20\x30\x20\x31\x2d\x31\x36\x2e\x38\x30\x34\
+\x2d\x31\x36\x2e\x38\x30\x35\x20\x31\x36\x2e\x38\x30\x34\x20\x31\
+\x36\x2e\x38\x30\x34\x20\x30\x20\x30\x20\x31\x20\x31\x36\x2e\x38\
+\x30\x34\x2d\x31\x36\x2e\x38\x30\x35\x7a\x22\x20\x66\x69\x6c\x6c\
+\x3d\x22\x23\x62\x66\x62\x66\x62\x66\x22\x20\x6f\x70\x61\x63\x69\
+\x74\x79\x3d\x22\x2e\x37\x35\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\
+\x77\x69\x64\x74\x68\x3d\x22\x2e\x32\x36\x34\x35\x38\x22\x2f\x3e\
+\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x01\xc1\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x31\x31\x2e\x36\x37\x20\x32\x31\x31\x2e\x36\x37\x22\x20\x78\x6d\
+\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\
+\x3e\x0a\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x30\x35\
+\x2e\x38\x33\x20\x30\x61\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\
+\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x2d\x31\x30\x35\x2e\x38\x33\
+\x20\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x31\
+\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x20\x31\x30\x35\x2e\
+\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\
+\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x20\x31\x30\
+\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\
+\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x2d\
+\x31\x30\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x7a\x6d\x2d\
+\x31\x35\x2e\x34\x35\x32\x20\x33\x34\x2e\x34\x30\x33\x68\x32\x38\
+\x2e\x31\x32\x38\x76\x33\x31\x2e\x38\x32\x39\x6c\x2d\x36\x2e\x36\
+\x36\x32\x31\x20\x36\x38\x2e\x38\x34\x68\x2d\x31\x34\x2e\x37\x31\
+\x32\x6c\x2d\x36\x2e\x37\x35\x34\x31\x2d\x36\x38\x2e\x38\x34\x76\
+\x2d\x33\x31\x2e\x38\x32\x39\x7a\x6d\x31\x2e\x31\x31\x20\x31\x30\
+\x39\x2e\x36\x34\x68\x32\x36\x76\x32\x36\x68\x2d\x32\x36\x76\x2d\
+\x32\x36\x7a\x22\x20\x66\x69\x6c\x6c\x3d\x22\x23\x66\x39\x30\x22\
+\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x2e\
+\x33\x31\x34\x37\x39\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\
+\x00\x00\x07\x54\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x38\x30\
+\x30\x20\x38\x30\x30\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\
+\x30\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\
+\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\
+\x2f\x73\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\
+\x36\x31\x2e\x34\x34\x20\x32\x31\x2e\x37\x34\x63\x31\x30\x2e\x39\
+\x36\x20\x30\x20\x32\x30\x2e\x38\x39\x20\x34\x2e\x34\x34\x20\x32\
+\x38\x2e\x30\x37\x20\x31\x31\x2e\x36\x33\x20\x37\x2e\x31\x38\x20\
+\x37\x2e\x31\x38\x20\x31\x31\x2e\x36\x33\x20\x31\x37\x2e\x31\x31\
+\x20\x31\x31\x2e\x36\x33\x20\x32\x38\x2e\x30\x37\x73\x2d\x34\x2e\
+\x34\x34\x20\x32\x30\x2e\x38\x39\x2d\x31\x31\x2e\x36\x33\x20\x32\
+\x38\x2e\x30\x37\x63\x2d\x37\x2e\x31\x38\x20\x37\x2e\x31\x38\x2d\
+\x31\x37\x2e\x31\x31\x20\x31\x31\x2e\x36\x33\x2d\x32\x38\x2e\x30\
+\x37\x20\x31\x31\x2e\x36\x33\x73\x2d\x32\x30\x2e\x38\x39\x2d\x34\
+\x2e\x34\x34\x2d\x32\x38\x2e\x30\x37\x2d\x31\x31\x2e\x36\x33\x63\
+\x2d\x37\x2e\x31\x38\x2d\x37\x2e\x31\x38\x2d\x31\x31\x2e\x36\x33\
+\x2d\x31\x37\x2e\x31\x31\x2d\x31\x31\x2e\x36\x33\x2d\x32\x38\x2e\
+\x30\x37\x73\x34\x2e\x34\x34\x2d\x32\x30\x2e\x38\x39\x20\x31\x31\
+\x2e\x36\x33\x2d\x32\x38\x2e\x30\x37\x63\x37\x2e\x31\x38\x2d\x37\
+\x2e\x31\x38\x20\x31\x37\x2e\x31\x31\x2d\x31\x31\x2e\x36\x33\x20\
+\x32\x38\x2e\x30\x37\x2d\x31\x31\x2e\x36\x33\x7a\x6d\x30\x2d\x32\
+\x31\x2e\x37\x34\x63\x31\x36\x2e\x39\x37\x20\x30\x20\x33\x32\x2e\
+\x33\x33\x20\x36\x2e\x38\x38\x20\x34\x33\x2e\x34\x34\x20\x31\x38\
+\x20\x31\x31\x2e\x31\x32\x20\x31\x31\x2e\x31\x32\x20\x31\x38\x20\
+\x32\x36\x2e\x34\x38\x20\x31\x38\x20\x34\x33\x2e\x34\x34\x20\x30\
+\x20\x31\x36\x2e\x39\x37\x2d\x36\x2e\x38\x38\x20\x33\x32\x2e\x33\
+\x33\x2d\x31\x38\x20\x34\x33\x2e\x34\x34\x2d\x31\x31\x2e\x31\x32\
+\x20\x31\x31\x2e\x31\x32\x2d\x32\x36\x2e\x34\x38\x20\x31\x38\x2d\
+\x34\x33\x2e\x34\x34\x20\x31\x38\x2d\x31\x36\x2e\x39\x37\x20\x30\
+\x2d\x33\x32\x2e\x33\x33\x2d\x36\x2e\x38\x38\x2d\x34\x33\x2e\x34\
+\x34\x2d\x31\x38\x2d\x31\x31\x2e\x31\x32\x2d\x31\x31\x2e\x31\x31\
+\x2d\x31\x38\x2d\x32\x36\x2e\x34\x37\x2d\x31\x38\x2d\x34\x33\x2e\
+\x34\x34\x73\x36\x2e\x38\x38\x2d\x33\x32\x2e\x33\x33\x20\x31\x38\
+\x2d\x34\x33\x2e\x34\x34\x63\x31\x31\x2e\x31\x31\x2d\x31\x31\x2e\
+\x31\x32\x20\x32\x36\x2e\x34\x37\x2d\x31\x38\x20\x34\x33\x2e\x34\
+\x34\x2d\x31\x38\x7a\x6d\x33\x32\x2e\x30\x33\x20\x32\x39\x2e\x34\
+\x31\x63\x2d\x38\x2e\x32\x2d\x38\x2e\x32\x2d\x31\x39\x2e\x35\x32\
+\x2d\x31\x33\x2e\x32\x37\x2d\x33\x32\x2e\x30\x33\x2d\x31\x33\x2e\
+\x32\x37\x73\x2d\x32\x33\x2e\x38\x33\x20\x35\x2e\x30\x37\x2d\x33\
+\x32\x2e\x30\x33\x20\x31\x33\x2e\x32\x37\x2d\x31\x33\x2e\x32\x37\
+\x20\x31\x39\x2e\x35\x32\x2d\x31\x33\x2e\x32\x37\x20\x33\x32\x2e\
+\x30\x33\x20\x35\x2e\x30\x37\x20\x32\x33\x2e\x38\x33\x20\x31\x33\
+\x2e\x32\x37\x20\x33\x32\x2e\x30\x33\x20\x31\x39\x2e\x35\x32\x20\
+\x31\x33\x2e\x32\x37\x20\x33\x32\x2e\x30\x33\x20\x31\x33\x2e\x32\
+\x37\x20\x32\x33\x2e\x38\x33\x2d\x35\x2e\x30\x37\x20\x33\x32\x2e\
+\x30\x33\x2d\x31\x33\x2e\x32\x37\x20\x31\x33\x2e\x32\x37\x2d\x31\
+\x39\x2e\x35\x32\x20\x31\x33\x2e\x32\x37\x2d\x33\x32\x2e\x30\x33\
+\x2d\x35\x2e\x30\x37\x2d\x32\x33\x2e\x38\x33\x2d\x31\x33\x2e\x32\
+\x37\x2d\x33\x32\x2e\x30\x33\x7a\x6d\x2d\x32\x38\x2e\x30\x32\x20\
+\x32\x37\x2e\x33\x36\x63\x2d\x31\x2e\x30\x32\x2d\x31\x2e\x30\x32\
+\x2d\x32\x2e\x34\x33\x2d\x31\x2e\x36\x35\x2d\x34\x2e\x30\x31\x2d\
+\x31\x2e\x36\x35\x2d\x31\x2e\x35\x37\x20\x30\x2d\x32\x2e\x39\x39\
+\x2e\x36\x33\x2d\x34\x2e\x30\x31\x20\x31\x2e\x36\x35\x6c\x2d\x2e\
+\x30\x31\x2e\x30\x31\x63\x2d\x31\x2e\x30\x32\x20\x31\x2e\x30\x32\
+\x2d\x31\x2e\x36\x35\x20\x32\x2e\x34\x33\x2d\x31\x2e\x36\x35\x20\
+\x34\x2e\x30\x31\x20\x30\x20\x31\x2e\x35\x37\x2e\x36\x33\x20\x32\
+\x2e\x39\x39\x20\x31\x2e\x36\x35\x20\x34\x2e\x30\x31\x6c\x2e\x30\
+\x31\x2e\x30\x31\x63\x31\x2e\x30\x32\x20\x31\x2e\x30\x32\x20\x32\
+\x2e\x34\x33\x20\x31\x2e\x36\x35\x20\x34\x2e\x30\x31\x20\x31\x2e\
+\x36\x35\x20\x31\x2e\x35\x37\x20\x30\x20\x32\x2e\x39\x39\x2d\x2e\
+\x36\x33\x20\x34\x2e\x30\x31\x2d\x31\x2e\x36\x35\x6c\x2e\x30\x31\
+\x2d\x2e\x30\x31\x63\x31\x2e\x30\x32\x2d\x31\x2e\x30\x32\x20\x31\
+\x2e\x36\x35\x2d\x32\x2e\x34\x34\x20\x31\x2e\x36\x35\x2d\x34\x2e\
+\x30\x31\x2d\x2e\x30\x31\x2d\x31\x2e\x35\x38\x2d\x2e\x36\x34\x2d\
+\x32\x2e\x39\x39\x2d\x31\x2e\x36\x36\x2d\x34\x2e\x30\x32\x7a\x6d\
+\x2d\x2e\x33\x39\x2d\x35\x2e\x39\x38\x63\x31\x2e\x34\x37\x2e\x35\
+\x34\x20\x32\x2e\x38\x20\x31\x2e\x33\x39\x20\x33\x2e\x38\x39\x20\
+\x32\x2e\x34\x38\x2e\x33\x37\x2e\x33\x37\x2e\x37\x32\x2e\x37\x37\
+\x20\x31\x2e\x30\x33\x20\x31\x2e\x32\x6c\x2e\x31\x2d\x2e\x30\x33\
+\x20\x32\x31\x2e\x30\x32\x2d\x35\x2e\x36\x33\x63\x2d\x31\x2e\x36\
+\x33\x2d\x33\x2e\x38\x33\x2d\x33\x2e\x39\x38\x2d\x37\x2e\x32\x38\
+\x2d\x36\x2e\x38\x38\x2d\x31\x30\x2e\x31\x37\x2d\x35\x2e\x30\x33\
+\x2d\x35\x2e\x30\x33\x2d\x31\x31\x2e\x37\x32\x2d\x38\x2e\x34\x31\
+\x2d\x31\x39\x2e\x31\x37\x2d\x39\x2e\x32\x34\x76\x32\x31\x2e\x31\
+\x32\x63\x2e\x30\x32\x2e\x30\x39\x2e\x30\x32\x2e\x31\x38\x2e\x30\
+\x31\x2e\x32\x37\x7a\x6d\x36\x2e\x39\x38\x20\x31\x30\x2e\x38\x34\
+\x63\x2d\x2e\x31\x34\x20\x31\x2e\x37\x33\x2d\x2e\x36\x39\x20\x33\
+\x2e\x33\x35\x2d\x31\x2e\x35\x37\x20\x34\x2e\x37\x36\x2e\x30\x35\
+\x2e\x30\x36\x2e\x30\x39\x2e\x31\x33\x2e\x31\x33\x2e\x32\x6c\x31\
+\x32\x2e\x30\x37\x20\x31\x39\x2e\x31\x33\x63\x2e\x35\x34\x2d\x2e\
+\x34\x37\x20\x31\x2e\x30\x36\x2d\x2e\x39\x36\x20\x31\x2e\x35\x37\
+\x2d\x31\x2e\x34\x37\x20\x35\x2e\x38\x33\x2d\x35\x2e\x38\x33\x20\
+\x39\x2e\x34\x34\x2d\x31\x33\x2e\x39\x20\x39\x2e\x34\x34\x2d\x32\
+\x32\x2e\x38\x20\x30\x2d\x31\x2e\x38\x37\x2d\x2e\x31\x36\x2d\x33\
+\x2e\x37\x2d\x2e\x34\x37\x2d\x35\x2e\x34\x39\x7a\x6d\x2d\x37\x2e\
+\x34\x37\x20\x39\x2e\x33\x32\x63\x2d\x2e\x39\x39\x2e\x33\x31\x2d\
+\x32\x2e\x30\x34\x2e\x34\x37\x2d\x33\x2e\x31\x33\x2e\x34\x37\x2d\
+\x2e\x39\x38\x20\x30\x2d\x31\x2e\x39\x33\x2d\x2e\x31\x33\x2d\x32\
+\x2e\x38\x34\x2d\x2e\x33\x38\x6c\x2d\x31\x31\x2e\x37\x38\x20\x31\
+\x39\x2e\x31\x35\x63\x34\x2e\x33\x39\x20\x32\x2e\x32\x34\x20\x39\
+\x2e\x33\x36\x20\x33\x2e\x35\x20\x31\x34\x2e\x36\x32\x20\x33\x2e\
+\x35\x20\x35\x2e\x34\x36\x20\x30\x20\x31\x30\x2e\x36\x2d\x31\x2e\
+\x33\x36\x20\x31\x35\x2e\x31\x31\x2d\x33\x2e\x37\x35\x7a\x6d\x2d\
+\x31\x32\x2d\x34\x2e\x33\x31\x63\x2d\x2e\x39\x32\x2d\x31\x2e\x33\
+\x38\x2d\x31\x2e\x35\x32\x2d\x32\x2e\x39\x39\x2d\x31\x2e\x37\x2d\
+\x34\x2e\x37\x31\x68\x2d\x2e\x30\x31\x6c\x2d\x32\x31\x2e\x30\x39\
+\x2d\x36\x2e\x36\x63\x2d\x2e\x33\x38\x20\x31\x2e\x39\x38\x2d\x2e\
+\x35\x38\x20\x34\x2e\x30\x32\x2d\x2e\x35\x38\x20\x36\x2e\x31\x31\
+\x20\x30\x20\x38\x2e\x39\x20\x33\x2e\x36\x31\x20\x31\x36\x2e\x39\
+\x37\x20\x39\x2e\x34\x34\x20\x32\x32\x2e\x38\x2e\x36\x33\x2e\x36\
+\x33\x20\x31\x2e\x32\x39\x20\x31\x2e\x32\x34\x20\x31\x2e\x39\x38\
+\x20\x31\x2e\x38\x32\x6c\x31\x31\x2e\x38\x2d\x31\x39\x2e\x31\x39\
+\x63\x2e\x30\x36\x2d\x2e\x30\x37\x2e\x31\x31\x2d\x2e\x31\x35\x2e\
+\x31\x36\x2d\x2e\x32\x33\x7a\x6d\x2e\x31\x35\x2d\x31\x31\x2e\x39\
+\x32\x63\x2e\x33\x36\x2d\x2e\x35\x31\x2e\x37\x36\x2d\x31\x20\x31\
+\x2e\x32\x31\x2d\x31\x2e\x34\x34\x20\x31\x2e\x30\x35\x2d\x31\x2e\
+\x30\x34\x20\x32\x2e\x33\x31\x2d\x31\x2e\x38\x37\x20\x33\x2e\x37\
+\x31\x2d\x32\x2e\x34\x31\x2d\x2e\x30\x31\x2d\x2e\x31\x31\x2d\x2e\
+\x30\x32\x2d\x2e\x32\x33\x2d\x2e\x30\x32\x2d\x2e\x33\x34\x76\x2d\
+\x32\x31\x2e\x31\x63\x2d\x37\x2e\x33\x38\x2e\x38\x37\x2d\x31\x34\
+\x20\x34\x2e\x32\x33\x2d\x31\x38\x2e\x39\x38\x20\x39\x2e\x32\x32\
+\x2d\x32\x2e\x37\x35\x20\x32\x2e\x37\x35\x2d\x35\x2e\x30\x31\x20\
+\x36\x2d\x36\x2e\x36\x33\x20\x39\x2e\x36\x7a\x22\x20\x73\x74\x72\
+\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x2e\x31\x35\x33\x36\
+\x22\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x73\x63\x61\
+\x6c\x65\x28\x36\x2e\x35\x31\x30\x34\x29\x22\x2f\x3e\x3c\x2f\x73\
+\x76\x67\x3e\
+\x00\x00\x01\xd6\
+\x3c\
+\x73\x76\x67\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\x6e\x65\x22\x20\
+\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\x20\x76\x69\x65\
+\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\
+\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\x20\x78\x6d\x6c\
+\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
+\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\
+\x3c\x67\x20\x73\x74\x72\x6f\x6b\x65\x3d\x22\x23\x30\x30\x30\x22\
+\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\
+\x22\x72\x6f\x75\x6e\x64\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\
+\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x22\x72\x6f\x75\x6e\x64\x22\x20\
+\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x32\x22\
+\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x35\x2e\x30\x30\
+\x30\x37\x20\x31\x32\x63\x30\x20\x31\x2e\x36\x35\x36\x39\x2d\x31\
+\x2e\x33\x34\x33\x31\x20\x33\x2d\x33\x20\x33\x2d\x31\x2e\x36\x35\
+\x36\x38\x20\x30\x2d\x32\x2e\x39\x39\x39\x39\x37\x2d\x31\x2e\x33\
+\x34\x33\x31\x2d\x32\x2e\x39\x39\x39\x39\x37\x2d\x33\x73\x31\x2e\
+\x33\x34\x33\x31\x37\x2d\x33\x20\x32\x2e\x39\x39\x39\x39\x37\x2d\
+\x33\x63\x31\x2e\x36\x35\x36\x39\x20\x30\x20\x33\x20\x31\x2e\x33\
+\x34\x33\x31\x20\x33\x20\x33\x7a\x22\x2f\x3e\x3c\x70\x61\x74\x68\
+\x20\x64\x3d\x22\x6d\x31\x32\x2e\x30\x30\x31\x32\x20\x35\x63\x2d\
+\x34\x2e\x34\x37\x37\x36\x36\x20\x30\x2d\x38\x2e\x32\x36\x37\x39\
+\x34\x20\x32\x2e\x39\x34\x32\x38\x38\x2d\x39\x2e\x35\x34\x32\x32\
+\x32\x20\x37\x20\x31\x2e\x32\x37\x34\x32\x36\x20\x34\x2e\x30\x35\
+\x37\x31\x20\x35\x2e\x30\x36\x34\x35\x36\x20\x37\x20\x39\x2e\x35\
+\x34\x32\x32\x32\x20\x37\x20\x34\x2e\x34\x37\x37\x36\x20\x30\x20\
+\x38\x2e\x32\x36\x37\x39\x2d\x32\x2e\x39\x34\x32\x39\x20\x39\x2e\
+\x35\x34\x32\x32\x2d\x37\x2d\x31\x2e\x32\x37\x34\x33\x2d\x34\x2e\
+\x30\x35\x37\x30\x39\x2d\x35\x2e\x30\x36\x34\x36\x2d\x37\x2d\x39\
+\x2e\x35\x34\x32\x32\x2d\x37\x7a\x22\x2f\x3e\x3c\x2f\x67\x3e\x3c\
+\x2f\x73\x76\x67\x3e\
+\x00\x00\x01\x1b\
+\x3c\
+\x73\x76\x67\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\x6e\x65\x22\x20\
+\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\x20\x76\x69\x65\
+\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\
+\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\x20\x78\x6d\x6c\
+\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
+\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\
+\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x2e\x30\x30\x30\x30\
+\x30\x30\x31\x20\x31\x32\x68\x32\x31\x2e\x39\x39\x39\x39\x39\x39\
+\x39\x6d\x30\x20\x30\x2d\x39\x2e\x34\x32\x38\x35\x37\x31\x2d\x39\
+\x2e\x35\x30\x30\x30\x30\x30\x32\x6d\x39\x2e\x34\x32\x38\x35\x37\
+\x31\x20\x39\x2e\x35\x30\x30\x30\x30\x30\x32\x2d\x39\x2e\x34\x32\
+\x38\x35\x37\x31\x20\x39\x2e\x34\x39\x39\x39\x39\x39\x22\x20\x73\
+\x74\x72\x6f\x6b\x65\x3d\x22\x23\x30\x30\x30\x22\x20\x73\x74\x72\
+\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\x22\x72\x6f\x75\
+\x6e\x64\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\
+\x6f\x69\x6e\x3d\x22\x72\x6f\x75\x6e\x64\x22\x20\x73\x74\x72\x6f\
+\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x2e\x39\x39\x39\x39\
+\x39\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x01\x23\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\
+\x20\x32\x34\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
+\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
+\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x32\
+\x20\x30\x61\x38\x2e\x34\x20\x38\x2e\x34\x20\x30\x20\x30\x20\x30\
+\x20\x2d\x34\x2e\x38\x20\x31\x35\x2e\x32\x38\x38\x76\x32\x2e\x37\
+\x31\x32\x61\x31\x2e\x32\x20\x31\x2e\x32\x20\x30\x20\x30\x20\x30\
+\x20\x31\x2e\x32\x20\x31\x2e\x32\x68\x37\x2e\x32\x61\x31\x2e\x32\
+\x20\x31\x2e\x32\x20\x30\x20\x30\x20\x30\x20\x31\x2e\x32\x2d\x31\
+\x2e\x32\x76\x2d\x32\x2e\x37\x31\x32\x61\x38\x2e\x34\x20\x38\x2e\
+\x34\x20\x30\x20\x30\x20\x30\x20\x2d\x34\x2e\x38\x2d\x31\x35\x2e\
+\x32\x38\x38\x7a\x6d\x2d\x33\x2e\x36\x20\x32\x32\x2e\x38\x61\x31\
+\x2e\x32\x20\x31\x2e\x32\x20\x30\x20\x30\x20\x30\x20\x31\x2e\x32\
+\x20\x31\x2e\x32\x68\x34\x2e\x38\x61\x31\x2e\x32\x20\x31\x2e\x32\
+\x20\x30\x20\x30\x20\x30\x20\x31\x2e\x32\x2d\x31\x2e\x32\x76\x2d\
+\x31\x2e\x32\x68\x2d\x37\x2e\x32\x7a\x22\x2f\x3e\x3c\x2f\x73\x76\
+\x67\x3e\
+\x00\x00\x02\xca\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\
+\x22\x38\x30\x30\x70\x78\x22\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\
+\x6e\x65\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x34\x20\x32\x34\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\
+\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\
+\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\x0a\x20\x3c\x70\x61\x74\x68\
+\x20\x64\x3d\x22\x6d\x31\x33\x2e\x37\x30\x37\x20\x31\x2e\x32\x39\
+\x32\x39\x63\x30\x2e\x33\x39\x30\x35\x20\x30\x2e\x33\x39\x30\x35\
+\x33\x20\x30\x2e\x33\x39\x30\x35\x20\x31\x2e\x30\x32\x33\x37\x20\
+\x30\x20\x31\x2e\x34\x31\x34\x32\x6c\x2d\x31\x2e\x33\x30\x31\x38\
+\x20\x31\x2e\x33\x30\x31\x38\x63\x34\x2e\x37\x38\x32\x34\x20\x30\
+\x2e\x32\x31\x31\x39\x33\x20\x38\x2e\x35\x39\x34\x37\x20\x34\x2e\
+\x31\x35\x36\x33\x20\x38\x2e\x35\x39\x34\x37\x20\x38\x2e\x39\x39\
+\x31\x20\x30\x20\x34\x2e\x39\x37\x30\x36\x2d\x34\x2e\x30\x32\x39\
+\x34\x20\x39\x2d\x39\x20\x39\x2d\x34\x2e\x39\x37\x30\x36\x20\x30\
+\x2d\x39\x2d\x34\x2e\x30\x32\x39\x34\x2d\x39\x2d\x39\x20\x30\x2d\
+\x30\x2e\x35\x35\x32\x33\x20\x30\x2e\x34\x34\x37\x37\x32\x2d\x31\
+\x20\x31\x2d\x31\x73\x31\x20\x30\x2e\x34\x34\x37\x37\x20\x31\x20\
+\x31\x63\x30\x20\x33\x2e\x38\x36\x36\x20\x33\x2e\x31\x33\x34\x20\
+\x37\x20\x37\x20\x37\x20\x33\x2e\x38\x36\x36\x20\x30\x20\x37\x2d\
+\x33\x2e\x31\x33\x34\x20\x37\x2d\x37\x20\x30\x2d\x33\x2e\x37\x32\
+\x32\x36\x2d\x32\x2e\x39\x30\x35\x38\x2d\x36\x2e\x37\x36\x36\x35\
+\x2d\x36\x2e\x35\x37\x33\x2d\x36\x2e\x39\x38\x37\x32\x6c\x31\x2e\
+\x32\x38\x30\x31\x20\x31\x2e\x32\x38\x30\x31\x63\x30\x2e\x33\x39\
+\x30\x35\x20\x30\x2e\x33\x39\x30\x35\x33\x20\x30\x2e\x33\x39\x30\
+\x35\x20\x31\x2e\x30\x32\x33\x37\x20\x30\x20\x31\x2e\x34\x31\x34\
+\x32\x2d\x30\x2e\x33\x39\x30\x35\x20\x30\x2e\x33\x39\x30\x35\x32\
+\x2d\x31\x2e\x30\x32\x33\x37\x20\x30\x2e\x33\x39\x30\x35\x32\x2d\
+\x31\x2e\x34\x31\x34\x32\x20\x30\x6c\x2d\x33\x2d\x33\x63\x2d\x30\
+\x2e\x31\x38\x37\x35\x33\x2d\x30\x2e\x31\x38\x37\x35\x34\x2d\x30\
+\x2e\x32\x39\x32\x38\x39\x2d\x30\x2e\x34\x34\x31\x38\x39\x2d\x30\
+\x2e\x32\x39\x32\x38\x39\x2d\x30\x2e\x37\x30\x37\x31\x31\x73\x30\
+\x2e\x31\x30\x35\x33\x36\x2d\x30\x2e\x35\x31\x39\x35\x37\x20\x30\
+\x2e\x32\x39\x32\x38\x39\x2d\x30\x2e\x37\x30\x37\x31\x31\x6c\x33\
+\x2d\x33\x63\x30\x2e\x33\x39\x30\x35\x2d\x30\x2e\x33\x39\x30\x35\
+\x32\x20\x31\x2e\x30\x32\x33\x37\x2d\x30\x2e\x33\x39\x30\x35\x32\
+\x20\x31\x2e\x34\x31\x34\x32\x20\x30\x7a\x22\x20\x63\x6c\x69\x70\
+\x2d\x72\x75\x6c\x65\x3d\x22\x65\x76\x65\x6e\x6f\x64\x64\x22\x20\
+\x66\x69\x6c\x6c\x3d\x22\x23\x30\x30\x30\x22\x20\x66\x69\x6c\x6c\
+\x2d\x72\x75\x6c\x65\x3d\x22\x65\x76\x65\x6e\x6f\x64\x64\x22\x2f\
+\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x01\x14\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\
+\x32\x20\x35\x31\x32\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\
+\x30\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\
+\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\
+\x2f\x73\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\
+\x33\x31\x30\x2e\x33\x39\x31\x20\x35\x30\x34\x2e\x36\x32\x35\x68\
+\x32\x30\x31\x2e\x36\x30\x39\x76\x2d\x33\x31\x34\x2e\x33\x31\x32\
+\x6c\x2d\x32\x35\x35\x2e\x39\x36\x39\x2d\x31\x38\x32\x2e\x39\x33\
+\x38\x2d\x32\x35\x36\x2e\x30\x33\x31\x20\x31\x38\x32\x2e\x39\x33\
+\x38\x76\x33\x31\x34\x2e\x33\x31\x32\x68\x32\x30\x31\x2e\x36\x30\
+\x39\x76\x2d\x31\x36\x37\x2e\x39\x35\x33\x68\x31\x30\x38\x2e\x37\
+\x38\x32\x7a\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\
+\x68\x3d\x22\x2e\x39\x38\x35\x34\x39\x31\x22\x20\x74\x72\x61\x6e\
+\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\x78\x28\x31\x20\
+\x30\x20\x30\x20\x31\x2e\x30\x32\x39\x36\x36\x33\x32\x20\x30\x20\
+\x2d\x37\x2e\x35\x39\x33\x37\x36\x36\x29\x22\x2f\x3e\x3c\x2f\x73\
+\x76\x67\x3e\
+\x00\x00\x02\x10\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x31\x31\x2e\x36\x37\x20\x32\x31\x31\x2e\x36\x37\x22\x20\x78\x6d\
+\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\
+\x3e\x0a\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x30\x35\
+\x2e\x38\x33\x20\x34\x65\x2d\x36\x61\x31\x30\x35\x2e\x38\x33\x20\
+\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x2d\x31\x30\x35\
+\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\
+\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\x20\x31\
+\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\
+\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\x20\x30\
+\x20\x31\x30\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x20\x31\
+\x30\x35\x2e\x38\x33\x20\x31\x30\x35\x2e\x38\x33\x20\x30\x20\x30\
+\x20\x30\x2d\x31\x30\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\
+\x7a\x6d\x2d\x35\x36\x2e\x34\x37\x33\x20\x34\x39\x2e\x33\x36\x68\
+\x31\x36\x2e\x36\x34\x6c\x33\x39\x2e\x38\x33\x34\x20\x33\x39\x2e\
+\x38\x33\x34\x20\x34\x30\x2e\x33\x33\x38\x2d\x33\x39\x2e\x38\x33\
+\x34\x68\x31\x36\x2e\x31\x33\x35\x76\x31\x36\x2e\x36\x34\x6c\x2d\
+\x33\x39\x2e\x38\x33\x34\x20\x33\x39\x2e\x38\x33\x34\x20\x33\x39\
+\x2e\x38\x33\x34\x20\x33\x39\x2e\x38\x33\x34\x76\x31\x36\x2e\x36\
+\x34\x68\x2d\x31\x36\x2e\x31\x33\x35\x6c\x2d\x34\x30\x2e\x33\x33\
+\x38\x2d\x33\x39\x2e\x38\x33\x34\x2d\x33\x39\x2e\x38\x33\x34\x20\
+\x33\x39\x2e\x38\x33\x34\x68\x2d\x31\x36\x2e\x36\x34\x76\x2d\x31\
+\x36\x2e\x31\x33\x35\x6c\x33\x39\x2e\x38\x33\x34\x2d\x34\x30\x2e\
+\x33\x33\x38\x2d\x33\x39\x2e\x38\x33\x34\x2d\x33\x39\x2e\x38\x33\
+\x34\x7a\x22\x20\x66\x69\x6c\x6c\x3d\x22\x23\x63\x30\x30\x22\x20\
+\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x2e\x33\
+\x31\x34\x37\x39\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x06\x8d\
+\x00\
+\x00\x1b\x84\x78\x9c\xdd\x19\xc9\x6e\xe3\xc6\xf2\x1c\x7f\x45\x83\
+\xbe\x24\x07\x96\xba\x7a\x6f\x8f\xe9\x20\x99\x64\xde\xf1\x1d\xde\
+\x9b\x0f\x50\x6c\x5a\x12\x42\x49\x86\xc8\xc8\x4b\x90\x7f\x0f\xaa\
+\x37\x52\x63\xd9\x98\x78\xc6\x1e\x20\x12\x20\x35\x8b\xb5\xef\x94\
+\xce\x7f\xbc\x5b\x77\x6c\xdf\xee\xfa\xd5\x76\xd3\x54\x08\xbc\x62\
+\xed\xe6\x72\x7b\xb5\xda\x2c\x9a\xea\xe3\xff\x3f\xd4\xae\xfa\xf1\
+\xe2\xe4\xbc\xdf\x2f\xd8\xed\xea\x6a\x58\x36\x95\xe0\x1c\xb0\x62\
+\xcb\x76\xb5\x58\x0e\xe5\x72\xc2\x82\xae\x56\xed\xed\xcf\xdb\xbb\
+\xa6\xe2\x8c\xb3\x80\xc1\x12\xde\xdd\xba\x3b\xeb\x6f\xe6\x97\x6d\
+\x53\xdd\xec\xda\xbe\xdd\xed\xdb\x00\xdc\xf4\x4d\xb5\x1c\x86\x9b\
+\xb3\xd9\xec\xf6\xf6\x16\x6e\x25\x6c\x77\x8b\x99\xe0\x9c\xcf\xfa\
+\xfd\xa2\x22\x15\x86\xfb\xae\x65\xc3\xfd\x4d\xdb\x54\x43\x7b\x37\
+\xcc\x2e\xfb\xbe\xba\x38\xf9\x0e\xfa\x81\xff\x79\xbd\xea\xba\xb3\
+\x3f\x76\xdd\xf7\xa7\xf3\x1f\xde\xfd\x15\x80\x18\x81\xa7\xe2\x57\
+\xee\x85\x4d\x40\x31\xc1\xfc\x2d\x63\xca\x08\xdc\x6c\x37\xed\xbb\
+\x7e\xd8\x6d\x7f\x6f\x0b\x55\xbc\xac\x83\xe9\x67\x08\x3a\x03\xd6\
+\xab\xa1\xdd\x75\xab\xf5\x6a\x38\x43\x9e\xd8\xa8\x3f\xb7\x37\xf3\
+\xcb\xd5\x70\x7f\xc6\xc1\xea\x04\xd4\x59\x8b\x0f\xc2\x4b\x99\x80\
+\xe6\x88\x40\x1e\x5e\x9f\x0a\xf4\xce\xba\xe7\x64\xda\xc4\xfe\xd7\
+\x5f\xac\x94\x3f\x27\xa0\x4b\xc0\x0f\xe1\x95\x80\xfe\x88\xcc\x84\
+\xf0\x0f\x65\x62\x72\xf7\x29\x0a\xf7\xfe\xbd\x7a\xf7\xd7\xc9\xf9\
+\x2c\x04\xe7\xe2\xe4\x7c\xc1\x86\xdd\x7c\xd3\x5f\x6f\x77\xeb\xa6\
+\x0a\xc7\x6e\x3e\xb4\xdf\xd7\xe8\x41\x33\x0d\x86\x73\xf5\x03\x05\
+\x8d\x5e\xe7\xdd\x6a\xd3\xce\x77\xff\xd9\xcd\xaf\x56\xed\x66\x60\
+\xab\xab\xa6\x9a\x57\xec\x0e\x9b\xca\x59\x40\x47\xd9\x22\x9a\x4a\
+\x10\xad\xaa\xd8\x3d\x36\x95\x97\x20\x4c\xc5\xee\x45\x39\x2e\x12\
+\xf5\xc7\xcd\x6a\xe8\x9b\xea\x8f\xbe\xdd\xfd\x8f\xd2\xeb\xbf\x9b\
+\x8f\x7d\x9b\x25\x7d\x77\xde\x0f\xdb\x1b\x46\x1f\xf5\xe5\xb6\xdb\
+\xee\x9a\xea\x94\x73\xf5\xc1\xbd\xaf\xd8\xf6\xfa\xba\x6f\x87\xa6\
+\xe2\xd5\xec\x59\xec\x9f\xf0\x17\x3f\x62\x83\xf2\x4a\x3d\x4b\x71\
+\x29\x27\xe8\x58\x50\xcf\x67\x87\x56\x67\xf0\xcd\x7c\x58\xb2\xcb\
+\x6e\xde\xf7\x4d\xd5\x0f\xbc\x62\x57\x4d\xb5\x46\xed\x00\x19\x5a\
+\x0e\x6e\x5f\x23\x98\xa5\x03\xbd\x47\x30\x0f\xeb\x1a\x2d\x18\xc6\
+\x23\xd4\x80\xc9\x50\x0f\xaa\x96\xa0\x23\x5c\xf8\x7c\x43\x6a\x10\
+\x8c\x03\x66\x78\x42\x57\xb2\x16\x60\xf6\xf4\xb1\x14\x08\xb8\xe7\
+\xa0\x97\x98\xa8\x96\xc4\xcd\x12\xe8\x61\xad\x24\xb8\x9a\x67\xbe\
+\x52\x01\x66\x0e\x0a\x6c\x2d\xc0\x26\x1e\x12\x4c\xe4\x61\xc0\x25\
+\x1e\x74\x8a\x3c\x14\xe0\x84\x87\x2d\xa6\x28\x03\x2e\xeb\xa1\x97\
+\xc2\x45\x0e\x0a\x7c\xe2\x40\x27\x02\xd5\xc2\x3d\xac\x95\x19\x79\
+\x28\x0e\x2a\xf3\x70\xa3\x25\x0a\x41\xef\x05\x81\x95\x03\x31\x41\
+\x37\x90\x0d\xd7\x22\xa8\x9d\x09\x5c\x26\xd0\x08\x6a\x42\xe0\xa2\
+\x15\x44\x20\xc1\x14\x3b\x3b\xa5\x92\x3b\x23\x91\x0c\x52\x54\x24\
+\xd2\x38\x12\x8d\x24\x24\x3c\xa3\x1b\xd0\x59\x86\x5e\x6a\x99\xed\
+\xa4\x13\x11\x39\x98\xd8\xa2\xe9\x14\xc8\xcc\x54\xb5\x4e\x0b\x70\
+\x41\x83\x20\x89\x83\xaf\x65\x8e\xae\x16\x20\x93\x02\x46\x04\xad\
+\x33\x2f\x03\xb2\xf0\x9a\xb8\x91\x9c\x91\x09\x64\x10\x6e\x63\x28\
+\x4c\x32\x71\x59\xd3\xe9\x61\x6d\x34\xd8\x09\xd9\xe8\x4e\x63\x40\
+\x8d\x72\x0c\x9f\xe8\x4c\x9e\x31\x49\x67\x9f\xbc\x56\x94\xa3\xf4\
+\x53\x85\x48\x14\x22\x92\x82\x11\x8e\x39\xa5\x94\x8b\x94\xcb\x3a\
+\x9c\x42\x4a\x61\xb4\x3a\xe0\x89\x98\x67\xe4\x7f\x99\x1c\x4a\xa7\
+\x80\x57\x1b\x05\x48\xd5\x92\x24\xa5\x48\x18\x1d\xaa\x25\x73\xc0\
+\x91\x03\x16\x0e\x98\x39\x58\xb0\x85\x03\xc5\x2c\x70\x40\xf0\xb5\
+\x03\xcb\x8c\xac\x13\xd7\xae\x36\x92\x45\x6f\x29\x56\xac\x1b\xad\
+\xf0\x20\x92\x15\x74\x0a\xbc\x25\xc8\x03\x3b\x74\xc6\xc4\x82\x59\
+\xb4\x08\x2e\x4c\x5a\xe8\x62\x87\x3d\xe0\x60\x52\x21\x53\xf6\x17\
+\x8f\x25\x59\x35\x02\x39\x4d\x14\xb5\xa2\x30\x9d\x10\x75\x46\x33\
+\x06\x7c\x11\x54\x52\x97\x83\x1e\xe5\x18\x0d\x2e\x81\x27\xc0\x1c\
+\x79\x13\xb2\x35\xab\xa4\xa3\x4a\x9d\x9a\xa4\x40\x17\x5c\x10\x90\
+\x62\x30\xc9\x88\x82\x1f\x4b\x5e\xd9\xdc\x8b\xc2\xa9\x84\x42\x16\
+\xdd\x14\xd8\x12\x4c\x57\x53\x86\x47\x0e\x2a\x3b\xdc\x66\xfa\x4c\
+\x2d\x62\xe3\x4c\xa9\xa0\x12\x35\x35\x84\x69\x10\x54\x0e\x82\x29\
+\x41\x28\xf2\xe5\x41\x2a\xe4\x9a\x52\x53\xe7\xa0\x8c\xf4\xbc\x04\
+\x91\x8f\x41\x54\xa0\x0b\x3d\x96\x5a\xd1\x70\x98\xce\x22\x72\x28\
+\x9d\x54\x95\x4e\x4a\x1a\x94\x34\xd0\xa5\x79\x85\x82\xd2\xa0\x19\
+\x9a\x50\xde\xc9\xe5\x32\x5c\x88\xe4\x72\x49\xb2\x23\xef\x8e\x9a\
+\xb3\x89\xc9\x4a\x6e\xa1\x7c\x4d\xee\xd3\xbe\x38\x06\x73\x6f\x49\
+\xb9\x95\xdc\x5a\xda\x56\x38\x25\xb5\x70\x74\x8c\xb6\xb9\x9e\x25\
+\x60\x6d\x72\xc6\xe9\x6c\xed\xa4\x2f\xeb\x71\x9c\x84\xc6\x34\x6d\
+\x58\xf6\x08\xba\x2c\x5d\x5f\x7b\xc0\x9a\xd2\x30\xf5\xca\xd4\x60\
+\xdd\x74\xd0\x68\x8c\xb6\x13\xba\x3d\xe0\x2e\x33\x77\xad\xa7\x5d\
+\x3f\xb4\xdc\x48\xc0\xc1\x4c\xfa\xaa\x2c\xb3\x26\x74\xbb\xdc\xd8\
+\x5d\xae\x0e\x1a\x23\x07\x72\x33\x1b\xe5\x27\xb3\x46\x4f\xd0\xfd\
+\xc1\xac\x11\x05\x7d\xda\x4d\xa5\x2f\x6a\xf2\xa0\x3e\x32\x65\x83\
+\xa0\x1c\x52\x1b\x43\x4a\x06\x52\x81\x62\x99\x82\xc9\xd7\x5a\x4c\
+\xfd\xa1\xf4\x38\x34\xfd\x74\x0a\x4a\x9f\x23\xa6\xa7\xe8\x58\xa6\
+\x89\x08\x09\x2e\x12\x7c\x9c\x32\x34\xda\x46\x36\xa5\xa7\x88\x34\
+\xe1\x97\x75\x38\xc5\x1d\x40\x1f\x0c\xe4\x91\x07\xcf\x1d\x2c\xec\
+\x06\xba\x8c\x50\x45\x69\xc9\x3f\x1d\xf7\x04\x9d\xa0\xab\x62\x91\
+\xb4\x23\xba\x54\x99\x3b\x11\x8e\x9a\x0b\x5e\x3c\x2d\x4d\x4c\xd8\
+\x00\x76\x13\xee\xa2\xa6\xba\x0e\xf0\x50\x89\x09\x5d\x8c\x3b\x17\
+\xca\xa4\x63\xc5\x68\x19\x6e\xaa\xf4\xf0\x51\x16\xbd\xaf\xfb\x79\
+\x6c\x57\xfe\x2d\xee\xca\xc2\x23\x58\x19\x77\x65\xe9\x24\x58\x9f\
+\x76\x65\x04\xa1\x5c\x5a\x96\xd3\xf9\x5f\xb2\x2d\x7f\x35\xaf\x1e\
+\x6e\xdd\x3a\x6e\xdd\x5e\x00\xe7\xc8\x50\x83\xf4\x7e\x4e\xc3\x26\
+\x0c\x1c\x7a\xd7\x16\x24\xe7\x8e\x8d\x5f\xe3\x3d\xf6\xfc\x3d\xe1\
+\x9d\xab\x8f\xdd\xab\x0f\xee\x3d\xac\x91\x16\x3b\xc3\x51\x9b\xa7\
+\x64\x13\xfa\xd7\x96\x4d\x5f\x94\xe2\xf4\x8c\x26\x98\x04\xe9\x9d\
+\x7a\x24\x3f\x0b\x7e\x4a\xc6\x73\x7e\x79\x4a\xfe\xe4\x5e\x68\x55\
+\x9e\x21\x59\xff\xd8\xf8\x24\xe0\xa8\xf1\x5f\x28\x3c\x19\x6f\x3c\
+\x33\xa0\xdf\x5e\xb0\xa3\x85\x40\x80\xf1\x5e\xbc\xc4\xe5\x4f\xa6\
+\x43\x7d\xec\xde\xa7\x2e\xaf\xbd\x63\x1e\xf0\x85\xb2\xbf\x2c\xdc\
+\x88\x1c\x1c\x93\xc7\xe3\xfd\xfa\xc9\x8e\x02\x19\x22\x88\x97\x55\
+\xf9\x93\xf9\xf0\x94\xdb\x0f\xab\x5c\xd2\x8f\x62\x0a\x04\xc7\xc7\
+\x8e\x7f\xa9\xe9\x9f\x9f\xea\x28\x0d\x08\x86\x02\xec\x37\x31\x9e\
+\xb6\x0a\xa6\x9e\xae\xb5\x57\x4c\x77\x54\x92\xd1\x8e\xf2\xf6\xa2\
+\x31\x2c\xdf\x0a\xb4\xf7\x4f\x76\xb7\xd7\xab\xb5\x1a\x15\x07\x4b\
+\xa6\x0b\x8e\x6f\x5f\x6c\x94\x70\x8e\xf2\xdd\x3b\xf7\x2d\x8c\xa7\
+\xdf\xc2\x28\xdf\x8f\x19\xff\xea\x0d\x1e\x05\x82\x62\x12\x3c\xe7\
+\x8f\x87\xea\x1b\x14\x3b\x72\x50\x0c\x39\x0d\xf5\xb7\xf7\xbd\x77\
+\xc1\x76\xfc\x9a\x3d\xfe\xf3\x6d\x77\xf4\xcb\x8f\x05\x77\x6c\x9d\
+\x79\xf5\x55\xce\x84\xc1\xca\xc4\xf1\x2e\xff\xfa\x0b\x8d\x0e\x4b\
+\x05\x7b\xdc\xeb\x5e\xbd\xdc\xa5\xa6\xc9\xc2\x10\xf8\x0b\x9b\xdd\
+\x97\x76\x79\x47\x6b\xe4\xb7\x58\x6a\xf2\xf3\xe0\xa9\xb8\xa6\x7f\
+\x7c\x2a\x96\xfe\x14\x6a\x2a\xb0\x3a\x3f\xd8\x9c\xcf\x16\x17\x27\
+\xf4\xb7\xc9\x7e\x71\x71\xf2\x37\x96\xc4\x29\x98\
+\x00\x00\x02\x0e\
+\x3c\
+\x73\x76\x67\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\x6e\x65\x22\x20\
+\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x36\x22\x20\x76\x69\x65\x77\
+\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x2e\x34\x38\x20\x2e\x34\x38\
+\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x31\x36\x22\x20\x78\x6d\x6c\
+\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
+\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\
+\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x2e\x34\x35\x33\x34\x31\
+\x35\x30\x35\x2e\x30\x36\x36\x35\x30\x34\x32\x33\x61\x2e\x30\x32\
+\x36\x36\x39\x34\x31\x32\x2e\x30\x32\x36\x36\x39\x34\x31\x32\x20\
+\x30\x20\x30\x20\x30\x20\x2d\x2e\x30\x31\x38\x39\x32\x36\x37\x2e\
+\x30\x30\x37\x37\x36\x37\x6c\x2d\x2e\x32\x37\x36\x38\x34\x37\x32\
+\x37\x2e\x32\x37\x34\x39\x31\x38\x34\x32\x2d\x2e\x31\x31\x32\x36\
+\x31\x36\x30\x34\x2d\x2e\x31\x31\x31\x37\x38\x31\x35\x61\x2e\x30\
+\x32\x36\x36\x39\x34\x31\x32\x2e\x30\x32\x36\x36\x39\x34\x31\x32\
+\x20\x30\x20\x30\x20\x30\x20\x2d\x2e\x30\x33\x37\x37\x34\x37\x30\
+\x36\x2e\x30\x30\x30\x31\x30\x33\x39\x32\x2e\x30\x32\x36\x36\x39\
+\x34\x31\x32\x2e\x30\x32\x36\x36\x39\x34\x31\x32\x20\x30\x20\x30\
+\x20\x30\x20\x2e\x30\x30\x30\x31\x30\x34\x33\x36\x2e\x30\x33\x37\
+\x37\x34\x37\x34\x6c\x2e\x31\x33\x31\x34\x33\x37\x33\x2e\x31\x33\
+\x30\x34\x39\x38\x39\x32\x61\x2e\x30\x32\x36\x36\x39\x36\x37\x39\
+\x2e\x30\x32\x36\x36\x39\x36\x37\x39\x20\x30\x20\x30\x20\x30\x20\
+\x2e\x30\x33\x37\x35\x39\x30\x38\x20\x30\x6c\x2e\x32\x39\x35\x37\
+\x32\x30\x37\x35\x2d\x2e\x32\x39\x33\x36\x33\x35\x33\x39\x61\x2e\
+\x30\x32\x36\x36\x39\x34\x31\x32\x2e\x30\x32\x36\x36\x39\x34\x31\
+\x32\x20\x30\x20\x30\x20\x30\x20\x2e\x30\x30\x30\x31\x30\x34\x33\
+\x36\x2d\x2e\x30\x33\x37\x37\x34\x37\x31\x2e\x30\x32\x36\x36\x39\
+\x34\x31\x32\x2e\x30\x32\x36\x36\x39\x34\x31\x32\x20\x30\x20\x30\
+\x20\x30\x20\x2d\x2e\x30\x31\x38\x38\x32\x30\x35\x2d\x2e\x30\x30\
+\x37\x38\x37\x31\x37\x7a\x22\x20\x66\x69\x6c\x6c\x3d\x22\x23\x30\
+\x30\x38\x30\x30\x30\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\
+\x6e\x65\x63\x61\x70\x3d\x22\x72\x6f\x75\x6e\x64\x22\x20\x73\x74\
+\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x22\x72\
+\x6f\x75\x6e\x64\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x01\x29\
+\x3c\
+\x73\x76\x67\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\x6e\x65\x22\x20\
+\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\x20\x76\x69\x65\
+\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\
+\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\x20\x78\x6d\x6c\
+\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
+\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\
+\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x2e\x30\x30\x30\x30\
+\x30\x35\x35\x20\x31\x32\x68\x32\x31\x2e\x39\x39\x39\x39\x38\x39\
+\x35\x6d\x2d\x32\x31\x2e\x39\x39\x39\x39\x38\x39\x35\x20\x30\x20\
+\x39\x2e\x34\x32\x38\x35\x36\x36\x35\x2d\x39\x2e\x34\x39\x39\x39\
+\x39\x35\x34\x6d\x2d\x39\x2e\x34\x32\x38\x35\x36\x36\x35\x20\x39\
+\x2e\x34\x39\x39\x39\x39\x35\x34\x20\x39\x2e\x34\x32\x38\x35\x36\
+\x36\x35\x20\x39\x2e\x34\x39\x39\x39\x39\x35\x22\x20\x73\x74\x72\
+\x6f\x6b\x65\x3d\x22\x23\x30\x30\x30\x22\x20\x73\x74\x72\x6f\x6b\
+\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\x22\x72\x6f\x75\x6e\x64\
+\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\
+\x6e\x3d\x22\x72\x6f\x75\x6e\x64\x22\x20\x73\x74\x72\x6f\x6b\x65\
+\x2d\x77\x69\x64\x74\x68\x3d\x22\x32\x2e\x30\x30\x30\x30\x31\x22\
+\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x01\xc8\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\
+\x20\x32\x34\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
+\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
+\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x32\
+\x20\x30\x63\x2d\x36\x2e\x36\x32\x34\x20\x30\x2d\x31\x32\x20\x35\
+\x2e\x33\x37\x36\x2d\x31\x32\x20\x31\x32\x73\x35\x2e\x33\x37\x36\
+\x20\x31\x32\x20\x31\x32\x20\x31\x32\x20\x31\x32\x2d\x35\x2e\x33\
+\x37\x36\x20\x31\x32\x2d\x31\x32\x2d\x35\x2e\x33\x37\x36\x2d\x31\
+\x32\x2d\x31\x32\x2d\x31\x32\x7a\x6d\x31\x2e\x32\x20\x32\x30\x2e\
+\x34\x68\x2d\x32\x2e\x34\x76\x2d\x32\x2e\x34\x68\x32\x2e\x34\x7a\
+\x6d\x32\x2e\x34\x38\x34\x2d\x39\x2e\x33\x2d\x31\x2e\x30\x38\x20\
+\x31\x2e\x31\x30\x34\x63\x2d\x2e\x38\x36\x34\x2e\x38\x37\x36\x2d\
+\x31\x2e\x34\x30\x34\x20\x31\x2e\x35\x39\x36\x2d\x31\x2e\x34\x30\
+\x34\x20\x33\x2e\x33\x39\x36\x68\x2d\x32\x2e\x34\x76\x2d\x2e\x36\
+\x63\x30\x2d\x31\x2e\x33\x32\x2e\x35\x34\x2d\x32\x2e\x35\x32\x20\
+\x31\x2e\x34\x30\x34\x2d\x33\x2e\x33\x39\x36\x6c\x31\x2e\x34\x38\
+\x38\x2d\x31\x2e\x35\x31\x32\x63\x2e\x34\x34\x34\x2d\x2e\x34\x33\
+\x32\x2e\x37\x30\x38\x2d\x31\x2e\x30\x33\x32\x2e\x37\x30\x38\x2d\
+\x31\x2e\x36\x39\x32\x20\x30\x2d\x31\x2e\x33\x32\x2d\x31\x2e\x30\
+\x38\x2d\x32\x2e\x34\x2d\x32\x2e\x34\x2d\x32\x2e\x34\x73\x2d\x32\
+\x2e\x34\x20\x31\x2e\x30\x38\x2d\x32\x2e\x34\x20\x32\x2e\x34\x68\
+\x2d\x32\x2e\x34\x63\x30\x2d\x32\x2e\x36\x35\x32\x20\x32\x2e\x31\
+\x34\x38\x2d\x34\x2e\x38\x20\x34\x2e\x38\x2d\x34\x2e\x38\x73\x34\
+\x2e\x38\x20\x32\x2e\x31\x34\x38\x20\x34\x2e\x38\x20\x34\x2e\x38\
+\x63\x30\x20\x31\x2e\x30\x35\x36\x2d\x2e\x34\x33\x32\x20\x32\x2e\
+\x30\x31\x36\x2d\x31\x2e\x31\x31\x36\x20\x32\x2e\x37\x7a\x22\x2f\
+\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x66\x35\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x02\x00\x00\x00\x02\x00\x08\x06\x00\x00\x00\xf4\x78\xd4\xfa\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0e\xc4\x00\x00\x0e\xc4\
+\x01\x95\x2b\x0e\x1b\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x20\x00\x49\x44\
+\x41\x54\x78\x9c\xec\xdd\x77\xbc\xdc\x55\x9d\x3f\xfe\xd7\x39\x9f\
+\x32\xe5\xce\x9d\x5b\xd2\x80\x84\x26\xbd\x08\x04\x11\xac\x10\x85\
+\xdc\x12\x08\x90\xc4\xe8\xae\xab\xdf\xb5\x62\x5b\x51\x5c\x14\x57\
+\x20\x99\x44\x44\x5d\x8a\x88\x65\x2d\xfb\xb3\xaf\x65\xa3\x84\x9a\
+\xe4\x86\x45\x63\x03\xa4\x48\x51\xe9\x25\xa1\x26\x21\xf5\xb6\x99\
+\xf9\x94\x73\x7e\x7f\x4c\x02\x49\xc8\x2d\x73\xe7\xf3\x99\x33\xe5\
+\xf5\x7c\x3c\xf2\x20\xb9\x77\xe6\x9c\x17\x29\xf3\x79\x7f\xce\xe7\
+\x14\x80\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\
+\x9a\x85\x30\x1d\x80\xaa\x6f\xd6\xac\x9c\x9d\x4e\xe3\x8c\x30\x14\
+\x3d\x5a\x87\xa7\x28\xa5\x0e\xd2\x5a\xb5\x29\xa5\x92\x00\x84\x94\
+\x32\x2f\x84\xf5\xac\x65\x89\xfb\xa4\xb4\x57\x2b\xa5\xae\xef\xeb\
+\xcb\x6d\x31\x9d\x9b\x88\x88\xa2\xc3\x02\xa0\x09\xcc\x9a\x95\xb3\
+\x93\x49\xb1\x50\x29\xf5\x6e\xad\xc3\x53\x82\xc0\x9f\xac\x75\x79\
+\x7f\xf6\x96\x65\x15\xa4\xb4\x9e\x13\x42\xde\x6f\xdb\xd6\x6d\x89\
+\x84\xba\x6e\xf9\xf2\xdc\xc6\xb8\x32\x13\x11\x51\xbc\x58\x00\x34\
+\xa8\xee\xee\x5c\xa7\x10\xf8\x8f\x20\x08\xde\x15\x86\xc1\x0c\xad\
+\x75\xe4\x7f\xd6\x96\x65\xe5\x2d\xcb\x7e\x5c\x4a\xf9\x47\xcb\xc2\
+\xcf\x6f\xb9\x25\x77\x7b\xd4\x7d\x10\x11\x51\x3c\x58\x00\x34\x90\
+\x85\x0b\x73\x6e\x7f\x3f\x3e\xad\x54\xf8\x11\xdf\xf7\x0e\x46\x95\
+\xff\x7c\xa5\x14\x4a\x4a\xfb\x25\x29\xed\xbf\x4a\x89\x9b\x85\xc0\
+\xcf\x56\xae\xcc\xf5\x57\x33\x03\x11\x11\x8d\x0f\x0b\x80\x06\xd0\
+\xdd\xbd\xe4\x4c\xad\xc3\xcb\x3d\xcf\x7b\x2d\x10\xfd\x9d\xfe\x44\
+\x09\x21\x20\xa5\xbd\xcd\xb6\xc5\xfd\x80\xf8\x75\x36\x2b\x7f\xbc\
+\x6c\x59\x6e\xd0\x74\x2e\x22\x22\x62\x01\x50\xc7\x72\xb2\xa7\x07\
+\x8b\x82\xc0\x3f\x3f\x08\xc2\x0e\x40\x9b\x0e\x34\x2e\xb6\xed\x6c\
+\xb6\x2c\x79\x8f\x94\xf6\xff\xe6\xf3\xea\xe7\x6b\xd6\xe4\x0a\xa6\
+\x33\x11\x11\x35\x23\x16\x00\x75\x66\xd6\xac\x9c\xed\xba\xf8\xcf\
+\x30\xf4\x3e\x1a\x86\x61\xca\x74\x9e\x0a\x69\xdb\x76\x36\x4a\x69\
+\xdf\x69\xdb\xe2\x87\x2b\x56\x2c\xbe\xc1\x74\x20\x22\xa2\x66\xc1\
+\x02\xa0\x8e\x74\x77\xe7\x3e\x17\x04\x5e\xae\x01\x2e\xfc\x7b\x25\
+\xa5\x50\x96\xe5\xac\x15\xc2\xba\xc1\x75\xb3\x57\xdd\x7c\xf3\x67\
+\x9e\x37\x9d\x89\x88\xa8\x51\xb1\x00\xa8\x03\x5d\x5d\x4b\xfe\x35\
+\x0c\xfd\x6b\xc2\xd0\x6f\x37\x9d\xa5\x7a\x04\x6c\xdb\xda\x62\x59\
+\xf6\x9f\x84\xb0\xbf\xbb\x6a\xd5\xa5\x2b\x4c\x27\x22\x22\x6a\x24\
+\x2c\x00\x6a\xd8\x9c\x39\x17\x1f\xe8\xfb\xd6\xcd\xbe\x5f\x3c\xd6\
+\x74\x16\xd3\xa4\xb4\x02\xcb\xb2\xff\x61\xdb\xf2\x47\x99\x0c\xbe\
+\xbd\x6c\x59\xce\x33\x9d\x89\x88\xa8\x9e\xb1\x00\xa8\x51\xdd\xdd\
+\x4b\xae\xf1\xfd\xc2\x27\x95\x52\xd2\x74\x96\x5a\x23\xa5\x54\x52\
+\xda\x4f\xd8\xb6\xf5\x0b\x21\x70\x35\x97\x1a\x12\x11\x95\x8f\x05\
+\x40\x8d\x39\xe7\x9c\xcb\xf6\x1f\x1e\x2e\xfc\xde\xf7\xfd\x83\x4d\
+\x67\xa9\x17\xb6\xed\x6c\xb0\x6d\xfb\x06\xdb\xce\x2e\xe5\xbc\x01\
+\x22\xa2\xf1\x61\x01\x50\x43\x7a\x7b\x73\x17\x16\x8b\xc5\xaf\x28\
+\xa5\x2c\xd3\x59\xea\x95\xe3\x38\x2f\x48\x69\xff\x02\xc0\xe5\x3c\
+\xbf\x80\x88\x68\x64\x2c\x00\x6a\x42\x4e\x76\x75\xe1\x66\xcf\xcb\
+\xf7\x9a\x4e\xd2\x28\x84\x10\xb0\x6d\xfb\x39\x21\xac\x1f\x25\x12\
+\xe2\xcb\x37\xdd\x94\x1b\x36\x9d\x89\x88\xa8\x96\xb0\x00\x30\xec\
+\xec\xb3\xaf\x99\x36\x3c\xbc\xe9\xde\x20\xf0\xa7\x9b\xce\xd2\xb8\
+\x84\x76\x1c\xe7\x69\x29\xad\xef\xf6\xf5\xe1\x4a\x20\xa7\x4c\x27\
+\x22\x22\x32\x8d\x05\x80\x41\x73\xe7\x2e\x3d\x6d\x68\xa8\xd0\xa7\
+\x54\x98\x30\x9d\xa5\x59\x08\x21\x7d\xdb\xb6\xff\x28\x84\xf3\x85\
+\xd5\xab\x17\xfd\xc5\x74\x1e\x22\x22\x53\x58\x00\x18\xd2\xdb\xfb\
+\xc5\x73\x8b\xc5\xa1\x5f\x2b\xa5\xf9\xbc\xdf\x10\xdb\xb6\xb7\xd8\
+\xb6\xf3\x6b\xc7\xc1\xc5\x37\xdd\x94\xdb\x64\x3a\x0f\x11\x51\x35\
+\xb1\x00\x30\x60\xce\x9c\xdc\x47\x87\x87\x0b\xdf\xae\xa5\x83\x7b\
+\x9a\x99\x10\x42\xdb\xb6\xf3\x88\xe3\x58\x97\xad\x58\x91\xfb\xb9\
+\xe9\x3c\x44\x44\xd5\xc0\x0b\x50\x95\x75\x77\xe7\x96\x14\x8b\xf9\
+\x45\xa6\x73\xd0\xde\x59\x96\x35\xec\x38\xf6\x32\xc7\x91\x17\x72\
+\x54\x80\x88\x1a\x19\x0b\x80\x2a\xea\xed\xcd\x5d\x98\xcf\xe7\xaf\
+\x30\x9d\x83\xc6\xb6\x73\x54\x20\x91\xb0\x2f\xba\xf9\xe6\xc5\x37\
+\x99\xce\x43\x44\x14\x35\x16\x00\x55\xd2\xd3\xb3\xe8\x83\xc5\x62\
+\xf1\xfb\x5a\xf3\xf7\xbc\xde\xd8\xb6\xbd\x45\x4a\xe7\xc7\x9e\x87\
+\x2f\xf0\xf8\x62\x22\x6a\x14\xbc\x18\x55\x41\x77\x77\xee\x9d\x9e\
+\x57\xf8\xa5\xd6\x7c\xe6\x5f\xcf\xa4\xb4\x02\xc7\x71\xfb\x92\x49\
+\xfb\x63\x37\xdc\x70\xc9\xb3\xa6\xf3\x10\x11\x55\x82\x17\xa4\x98\
+\xcd\x99\xf3\xa5\x13\x0a\x85\x81\x7b\x38\xdb\xbf\x71\x08\x01\x6d\
+\xdb\x89\xfb\x5d\x57\xfe\xdb\x2d\xb7\xe4\x6e\x37\x9d\x87\x88\x68\
+\x22\x58\x00\xc4\xe8\xdc\x73\x73\xed\x03\x03\xfe\xb3\x61\x18\x64\
+\x4c\x67\xa1\x78\xd8\xb6\xb3\xc1\xb2\xec\x4b\xfa\xfa\x72\xff\x6d\
+\x3a\x0b\x11\x51\x39\x58\x00\xc4\xe8\x8c\x33\x2e\x7d\x32\x08\xbc\
+\xd7\x98\xce\x41\xf1\xb3\x2c\x7b\x9b\x6d\xdb\xd7\xf6\xf5\x89\x25\
+\xdc\x69\x90\x88\xea\x01\x0b\x80\x98\x74\x75\x2d\x5e\xee\x79\x85\
+\x73\x4d\xe7\xa0\xea\x92\xd2\x2e\x24\x12\xf6\x77\xf2\x79\xf1\xd9\
+\x35\x6b\x72\x81\xe9\x3c\x44\x44\x23\x61\x01\x10\x83\xde\xde\xdc\
+\x3b\x0a\x85\xfc\x32\xad\x4d\x27\x21\x53\x84\x90\x7e\x22\x91\xf8\
+\x55\xa1\x80\x0f\x73\xe5\x00\x11\xd5\x22\x16\x00\x11\x5b\xb8\xf0\
+\xa2\xb6\x2d\x5b\xac\xf5\x61\x18\x26\x4d\x67\x21\xf3\xa4\x94\x81\
+\x6d\x3b\x37\x59\x96\x7c\xdf\xca\x95\xb9\x7e\xd3\x79\x88\x88\x76\
+\x62\x01\x10\xb1\xae\xae\x45\xf7\x7a\x5e\xf1\x44\xd3\x39\xa8\xb6\
+\x48\x69\x05\x96\x65\xff\x22\x99\x94\x1f\xe5\xd1\xc4\x44\x54\x0b\
+\x58\x00\x44\x68\xce\x9c\xdc\xf9\xc3\xc3\xf9\xaf\x9b\xce\x41\xb5\
+\x4b\x4a\xe9\x3b\x4e\xe2\xbb\xc5\x22\x2e\xe0\x1c\x01\x22\x32\x89\
+\x05\x40\x44\xe6\xce\xcd\xa5\x87\x86\xfc\xcd\x4a\x05\x1c\xfa\xa7\
+\x31\x49\x29\x8b\xb6\x9d\xf8\xf6\xea\xd5\xb8\x90\xab\x06\x88\xc8\
+\x04\x69\x3a\x40\xa3\xf0\xfd\x70\x19\x2f\xfe\x34\x5e\x4a\xa9\x84\
+\xe7\xe5\x2f\x38\xfd\x74\x7f\x7b\x6f\x6f\xee\x42\xd3\x79\x88\xa8\
+\xf9\x70\x04\x20\x02\x3d\x3d\x4b\x5f\x5f\x28\x0c\xfd\x05\xfc\xfd\
+\xa4\x09\xb2\x6d\x7b\x93\xeb\xba\x1f\x5a\xb1\x62\xf1\x0d\xa6\xb3\
+\x10\x51\x73\xe0\x05\x2b\x02\xb3\x67\x5f\xfa\xb4\xef\x7b\x07\x99\
+\xce\x41\xf5\xcf\x71\xdc\xc7\xa4\x74\xe6\xf7\xf5\x2d\xfa\x87\xe9\
+\x2c\x44\xd4\xd8\x58\x00\x54\xa8\xa7\xe7\xb2\x79\x85\xc2\xc0\x75\
+\xa6\x73\x50\x23\x11\x70\x1c\xf7\xf7\x2d\x2d\xf2\xdc\xeb\xaf\xcf\
+\x6d\x33\x9d\x86\x88\x1a\x13\xe7\x00\x54\x28\x08\x0a\xdf\x32\x9d\
+\x81\x1a\x8d\x86\xef\x17\x4f\xeb\xef\x2f\xbe\xd4\xdd\xbd\xe4\x1a\
+\xd3\x69\x88\xa8\x31\x71\x04\xa0\x02\x73\xe6\x2c\x7d\xf7\xf0\xf0\
+\xd0\xff\x98\xce\x41\x8d\xcd\xb2\x9c\x6d\xae\x9b\x78\xff\xca\x95\
+\x97\x5e\x6f\x3a\x0b\x11\x35\x0e\x16\x00\x15\x38\xe3\x8c\x4b\x5e\
+\x0c\x02\x7f\x1f\xd3\x39\xa8\x39\x38\x4e\xe2\x81\x44\xa2\xfd\xcc\
+\x9b\x6f\xfe\xcc\xf3\xa6\xb3\x10\x51\xfd\xe3\x23\x80\x09\x9a\x33\
+\x27\x77\x16\x2f\xfe\x54\x4d\xbe\x5f\x3c\x7e\x78\xf8\xa5\x75\xdd\
+\xdd\xb9\x6f\x03\x9a\xc5\x3b\x11\x55\x84\x1f\x22\x13\x34\x7b\xf6\
+\xa5\x0f\xf9\xbe\x77\x94\xe9\x1c\xd4\x9c\x1c\xc7\xd9\x6a\x59\x89\
+\xf7\xac\x5a\x75\xe9\x0a\xd3\x59\x88\xa8\x3e\xb1\x00\x98\x80\xb9\
+\x73\xbf\x78\xf0\xe0\xe0\xd0\x53\x9a\xc7\xfd\x91\x41\x42\x08\x38\
+\x8e\x7b\xa7\x65\xc9\x6e\x1e\x34\x44\x44\xe5\xe2\x23\x80\x09\xf0\
+\xbc\xf0\x6a\x5e\xfc\xc9\x34\xad\x35\x3c\xaf\xf8\x06\xcf\xf3\x36\
+\x74\x77\xe7\x3e\x64\x3a\x0f\x11\xd5\x17\x8e\x00\x4c\xc0\xe9\xa7\
+\x7f\xa1\x10\x86\x61\xc2\x74\x0e\xa2\x5d\x39\x8e\xfb\xb0\x94\xc9\
+\xd3\xfb\xfa\x2e\x7e\xd1\x74\x16\x22\xaa\x7d\x1c\x01\x28\x53\x6f\
+\xef\x92\x0f\xf3\xe2\x4f\xb5\xc8\xf7\xbd\xa3\x7c\x7f\xe8\x99\x39\
+\x73\x96\xfc\x87\xe9\x2c\x44\x54\xfb\x38\x02\x50\xa6\xd9\xb3\x2f\
+\x79\xc8\xf7\x7d\x4e\xfe\xa3\x1a\x26\xe0\x38\xce\x43\xa9\xd4\xa4\
+\xb7\xdf\x78\xe3\xa7\x37\x98\x4e\x43\x44\xb5\x89\x23\x00\x65\x78\
+\xdf\xfb\x72\xc9\x20\x08\x8e\x34\x9d\x83\x68\x74\x1a\xbe\xef\x1d\
+\x3d\x38\xb8\xe1\xb9\xae\xae\x25\x9f\x34\x9d\x86\x88\x6a\x13\x0b\
+\x80\x32\xac\x5f\x2f\x3e\xa9\x35\xd7\x5f\x53\x7d\x50\x4a\xd9\x9e\
+\x97\xbf\x76\xf6\xec\x4b\x1f\x9a\x3b\x37\x37\xd9\x74\x1e\x22\xaa\
+\x2d\x2c\x00\xca\x10\x86\xe1\x7b\x4d\x67\x20\x2a\x8f\x86\xef\x7b\
+\x47\x0d\x0d\x15\x9f\xeb\xea\x5a\xf4\x2e\xd3\x69\x88\xa8\x76\xf0\
+\x6e\x76\x9c\x16\x2e\x5c\x68\x6d\xde\x7c\x48\x51\x29\x6d\x99\xce\
+\x42\x34\x31\x02\xae\x9b\x5c\xe9\x79\x38\x7b\xcd\x9a\x5c\x60\x3a\
+\x0d\x11\x99\xc5\x11\x80\x71\xea\xef\x3f\x66\x81\x94\x96\xe5\x38\
+\x0e\xf6\xfc\x61\x59\x36\x2c\xcb\x82\x94\x16\x84\x10\x10\x82\x75\
+\x15\xd5\x22\x0d\xcf\xcb\xf7\xda\x76\xf0\x7c\x57\xd7\xe5\x9c\xcb\
+\x42\xd4\xe4\x6c\xd3\x01\xea\x45\x26\x93\x39\xb2\x9c\xbd\x7f\xb4\
+\xd6\x3b\x7e\x84\x50\x4a\x41\x29\xbd\xe3\xbf\x21\xb4\x2e\xfd\x3a\
+\x0c\x4b\x3f\x27\xaa\xa6\x20\xf0\xa7\x4a\x39\xf0\x8f\xee\xee\xdc\
+\xa5\x7d\x7d\xb9\xcb\x4d\xe7\x21\x22\x33\x78\xab\x3a\x4e\xf3\xe7\
+\x5f\xf9\x7b\x00\xa7\x46\xdd\xae\xd6\x1a\x4a\x85\x08\xc3\x10\x4a\
+\x85\x08\x82\x10\x61\x18\x20\x0c\x39\x42\x4b\xf1\x73\x9c\xc4\x9d\
+\xbe\x2f\xdf\xb6\x66\x4d\xae\x60\x3a\x0b\x11\x55\x17\x0b\x80\x71\
+\x98\x3b\x37\x97\x76\x9c\xcc\x16\x00\x55\xdd\x00\xa8\x54\x08\x94\
+\x8a\x83\x20\xf0\x11\x04\x01\x47\x0c\x28\x72\x96\x65\x6f\x97\x32\
+\x3d\xeb\xd6\x5b\x2f\xbe\xdf\x74\x16\x22\xaa\x1e\xce\x01\x18\x07\
+\xd7\xcd\xbc\x15\x55\xbe\xf8\x03\x80\x65\xd9\x70\xdd\x04\x52\xa9\
+\x34\x5a\x5b\xdb\xd0\xd1\x31\x09\xed\xed\x9d\xc8\x64\xb2\x48\x26\
+\x53\xb0\x6d\x87\xf3\x0d\xa8\x62\x61\x18\xb4\x85\xe1\xe0\xbd\x3d\
+\x3d\xb9\xf3\x4d\x67\x21\xa2\xea\xe1\x1c\x80\x71\xd0\x5a\xbf\xb9\
+\x56\x06\x4b\xa4\xb4\xe0\xba\x16\x5c\xf7\x95\x7a\x64\xe7\xe8\x80\
+\xef\xfb\xf0\x7d\x0f\x00\x0f\x2a\xa2\xf2\x28\xa5\x64\xa1\x50\xf8\
+\xfa\xec\xd9\x8b\xe6\xfb\xbe\x3c\x83\xab\x04\x88\x1a\x1f\x47\x00\
+\xc6\x45\x9c\x6c\x3a\xc1\x68\x6c\xdb\x41\x32\x99\x42\x6b\x6b\x16\
+\x1d\x1d\x93\x90\xcd\xb6\x23\x99\x4c\xc3\xb2\x58\xdf\x51\x39\x34\
+\x7c\xbf\x78\x9a\x65\x85\xcf\x9e\x75\xd6\xd5\xd3\x4d\xa7\x21\xa2\
+\x78\xb1\x00\x18\x93\x16\x00\x4e\x32\x9d\x62\xbc\x84\x10\xb0\x6d\
+\x07\xe9\x74\x0b\xda\xda\x3a\xd0\xde\x3e\x09\x99\x4c\x2b\x12\x89\
+\x24\x84\xe0\x1f\x37\x8d\x2d\x0c\xbd\x7d\xf2\xf9\x4d\x4f\xf5\xf6\
+\x7e\xa9\xd7\x74\x16\x22\x8a\x0f\x37\xb5\x19\xc3\xbc\x79\xd9\xc3\
+\x85\xc0\xe7\x4c\xe7\x98\x28\x21\xc4\xcb\x73\x09\x92\xc9\x34\x12\
+\x89\x04\xa4\xb4\xa0\x94\x82\x2e\x67\x5d\x23\x35\x15\xad\xb5\x15\
+\x04\xc5\x77\x1f\x71\xc4\x6c\xe7\xc9\x27\xd7\xfc\xd6\x74\x1e\x22\
+\x8a\x1e\x6f\x09\xc7\xa4\x4e\x34\x9d\x20\x2a\x42\x94\x26\x16\xa6\
+\x52\x69\xb4\xb7\x77\xa2\xad\xad\x03\xa9\x54\x0b\x1f\x15\xd0\x48\
+\x44\xb1\x58\xb8\xb8\xab\x6b\xf1\x2d\xa6\x83\x10\x51\xf4\x58\x00\
+\x8c\x41\x08\x71\x8c\xe9\x0c\x71\xd9\x59\x0c\xb4\xb5\x75\xa0\xad\
+\xad\x13\xa9\x54\x1a\x52\xf2\xaf\x04\xed\x4a\xc3\xf3\x0a\x73\x66\
+\xcf\xbe\xe4\xa9\xde\xde\x5c\xd6\x74\x1a\x22\x8a\x0e\x3f\xed\xc7\
+\x20\x04\x8e\x36\x9d\xa1\x1a\x2c\xcb\x42\x2a\xd5\x82\xb6\xb6\xd2\
+\x24\xc2\x44\x22\xc5\x25\x86\xf4\x32\xdf\xf7\x0f\xf6\x3c\xff\xf9\
+\xde\xde\x5c\x53\xfc\x7b\x20\x6a\x06\x2c\x00\xc6\xa0\xb5\x3e\xca\
+\x74\x86\x6a\x12\xa2\xb4\xaa\xa0\xa5\x25\xb3\x63\x02\x61\x16\x8e\
+\xe3\x9a\x8e\x45\x35\x20\x0c\x83\x4c\xb1\x58\xbc\x7f\xce\x9c\x2f\
+\xf6\x98\xce\x42\x44\x95\xe3\x2d\xde\x28\xce\x3b\xef\xbb\xce\xa6\
+\x4d\x03\x43\x00\x1c\xd3\x59\x4c\x53\x4a\xa1\x58\x2c\xa0\x50\xc8\
+\x73\x37\xc2\x26\x27\x84\xd0\x89\x44\xf2\xd3\xab\x56\xe5\xae\x35\
+\x9d\x85\x88\x26\x8e\x23\x00\xa3\xd8\xb8\x71\xfb\x01\xe0\xc5\x1f\
+\x00\x20\xa5\x44\x2a\x95\x46\x47\x47\xe7\x8e\x51\x01\xfe\xb6\x34\
+\x2b\xad\xb5\x28\x14\x0a\x5f\xef\xee\x5e\xf4\x6d\xd3\x59\x88\x68\
+\xe2\x58\x00\x8c\x42\x08\x71\xa0\xe9\x0c\xb5\x47\xc0\x75\x13\x68\
+\x6d\x6d\x47\x5b\x5b\x27\x12\x89\x94\xe9\x40\x64\x84\x46\xb1\xe8\
+\x7d\xac\xbb\x3b\x77\xb3\xe9\x24\x44\x34\x31\x2c\x00\x46\xc7\x02\
+\x60\x14\x96\x65\xa1\xa5\x25\x83\x8e\x8e\xc9\x48\xa7\x33\xdc\x68\
+\xa8\xe9\x68\x14\x8b\xf9\x33\x67\xcf\x5e\x74\xff\xac\x59\x39\xae\
+\x25\x25\xaa\x33\xfc\xc4\x1e\x85\x10\x2c\x00\xc6\x43\x08\x81\x64\
+\x32\xb5\xe3\xf1\x40\x2b\x2c\x8b\xfb\x4b\x35\x13\xdf\x2f\x1e\xef\
+\x38\xc1\x63\x73\xe7\xe6\xd2\xa6\xb3\x10\xd1\xf8\xb1\x00\x18\x85\
+\xd6\x62\x7f\xd3\x19\xea\x8b\x80\xeb\x26\x91\xcd\x96\xe6\x09\xd8\
+\x36\xe7\x09\x34\x0b\xdf\xf7\x0f\xce\xe7\xfd\xb5\x73\xe7\xe6\x26\
+\x9b\xce\x42\x44\xe3\xc3\x02\x60\x14\x42\x60\x9a\xe9\x0c\xf5\x48\
+\x08\xc0\x75\x13\xc8\x66\xdb\x91\xcd\xb6\xc3\xb6\xb9\x8c\xb0\x19\
+\x04\x41\x30\x25\x9f\x0f\x9e\xe0\x41\x42\x44\xf5\x81\x05\xc0\xe8\
+\xa6\x98\x0e\x50\xef\x6c\xdb\x41\x36\xdb\x86\xd6\xd6\x76\xd8\x36\
+\x1f\x13\x37\xba\x20\xf0\xdb\xf2\xf9\x4d\x8f\x9d\x75\xd6\x25\x87\
+\x99\xce\x42\x44\xa3\x63\x01\x30\x3a\x0e\x67\x46\xc4\x71\x1c\x64\
+\xb3\x1d\x68\x6d\x6d\xe7\xd9\x03\x0d\x2e\x0c\xc3\xf4\xf0\x70\xf8\
+\xb7\xd9\xb3\xbf\x74\x82\xe9\x2c\x44\x34\x32\x16\x00\xa3\xd0\x9a\
+\x05\x40\xd4\x1c\xc7\x41\x5b\x5b\x3b\x32\x99\x2c\x27\x0b\x36\x30\
+\xa5\x54\x42\xa9\xa1\x3b\x7b\x7b\x97\xce\x34\x9d\x85\x88\xf6\x8e\
+\x3b\x01\x8e\x60\xe1\xc2\xff\xb5\xc2\xf0\x19\x1f\xfc\x3d\x8a\x8d\
+\xd6\x80\xef\x17\x30\x34\x34\xc4\xdd\x05\x1b\x94\x65\x59\x9e\xeb\
+\x26\xdf\xb0\x72\xe5\xa2\xfb\x4c\x67\x21\xa2\xdd\x71\x04\x60\x04\
+\x83\x83\xeb\x5b\xc0\x8b\x7f\xac\x4a\x93\x05\x93\x68\x6f\xef\x44\
+\x2a\xd5\x02\x9e\x3d\xd4\x78\xc2\x30\x74\x8b\xc5\x02\x47\x02\x88\
+\x6a\x10\x0b\x80\x11\xa4\x52\x61\x8b\xe9\x0c\xcd\x42\x08\xb1\xe3\
+\x58\xe2\x49\x48\x24\x92\x60\xdd\xd5\x58\x94\x62\x11\x40\x54\x8b\
+\x58\x00\x8c\xc0\xb2\x34\x0b\x80\x2a\x93\x52\xa2\xa5\xa5\x15\xd9\
+\x6c\x1b\x27\x0a\x36\x18\xa5\x42\xd7\xf3\x0a\x77\x74\x75\x7d\xe9\
+\x58\xd3\x59\x88\xa8\x84\x05\xc0\x08\x82\x80\x05\x80\x29\xa5\xa5\
+\x83\x1d\x68\x69\x69\x85\xe0\x73\x81\x86\x11\x86\x61\x22\x0c\x87\
+\xee\x3a\xe7\x9c\xcb\xb8\xc1\x16\x51\x0d\x60\x01\x30\x02\x29\x05\
+\xb7\xb1\x33\x48\x08\x20\x91\x28\xcd\x0f\x28\x3d\x16\xa0\x46\x10\
+\x86\x61\x6a\x70\x70\xf8\x1f\xf3\xe6\xe5\xa6\x9a\xce\x42\xd4\xec\
+\x58\x00\x8c\x20\x0c\xf9\x7b\x53\x0b\x84\x28\x3d\x16\x28\xed\x1f\
+\xc0\x65\x83\x8d\x20\x0c\xc3\xd6\x81\x81\xe0\xc1\x59\xb3\x72\xac\
+\xec\x88\x0c\xe2\x45\x6e\x04\x52\x6a\xfe\xde\xd4\x90\x9d\x1b\x09\
+\xa5\x52\x7c\x32\xd3\x08\x82\xc0\x9f\xe6\x38\xc1\x43\x3c\x45\x90\
+\xc8\x1c\x5e\xe4\x46\x14\xf2\x76\xb3\xc6\xbc\xb2\x5a\xa0\x83\x07\
+\x0d\x35\x00\xdf\xf7\x0f\x76\x5d\x75\xaf\xe9\x1c\x44\xcd\x8a\x05\
+\x00\xd5\x1d\xcb\xb2\xd1\xda\xda\x8e\x74\x9a\x7b\x07\xd4\x3b\xcf\
+\x2b\x1e\x37\x7b\xf6\xa5\x7d\xa6\x73\x10\x35\x23\x16\x00\x23\x10\
+\x42\x04\xa6\x33\xd0\xc8\x84\x00\x92\xc9\x34\xb2\xd9\x4e\x2e\x19\
+\xac\x73\xbe\xef\x77\xf5\xf4\xe4\x7e\x6a\x3a\x07\x51\xb3\x61\x01\
+\x30\x02\xad\xb5\x6f\x3a\x03\x8d\xcd\xb2\x2c\xb4\xb5\x75\x20\x99\
+\x4c\x81\x1b\x08\xd5\x2b\x8d\x42\xa1\xf0\x9e\x9e\x9e\xdc\x15\xa6\
+\x93\x10\x35\x13\x16\x00\x23\x08\x43\x9b\x05\x40\x1d\x49\xa7\x33\
+\xc8\x66\xb9\x52\xa0\x7e\x69\x14\x0a\xf9\x0b\x7b\x7b\x97\x7e\xc0\
+\x74\x12\xa2\x66\xc1\x02\x60\x04\xb6\xad\x58\x00\xd4\x19\xdb\xb6\
+\x91\xcd\x76\x70\xdf\x80\x3a\x56\x2c\xe6\xbf\xdf\xd5\xb5\xf4\x14\
+\xd3\x39\x88\x9a\x01\x0b\x80\x11\x48\x29\x39\x07\xa0\x0e\x09\x21\
+\xd0\xd2\xd2\x8a\x4c\xa6\x8d\xbb\x08\xd6\x21\xa5\x94\x0c\xc3\xe2\
+\x6f\x17\x2e\xbc\x7c\x8a\xe9\x2c\x44\x8d\x8e\x05\xc0\x08\xc2\x90\
+\x23\x00\xf5\xcc\x75\x5d\xb4\xb5\x75\xc2\xb6\x39\x41\xb0\xde\x84\
+\x61\x90\xde\xba\x35\x7f\x3f\xf7\x08\x20\x8a\x17\x0b\x80\x11\x04\
+\x41\xc8\x02\xa0\xce\x49\x29\x91\xcd\xee\x9c\x20\x48\xf5\x24\x08\
+\xbc\xfd\x1c\x47\xdd\x66\x3a\x07\x51\x23\x63\x01\x30\x82\x44\x22\
+\xc5\x02\xa0\x41\xa4\xd3\x19\x3e\x12\xa8\x43\xbe\xef\x9d\xda\xd3\
+\x93\xfb\xa6\xe9\x1c\x44\x8d\x8a\x05\xc0\x08\x7c\x9f\x23\x00\x8d\
+\xc4\x75\x5d\x64\xb3\x1d\x5c\x25\x50\x57\x34\x0a\x85\xfc\x27\xb8\
+\x32\x80\x28\x1e\x2c\x00\x46\xe0\x38\x2e\x27\x01\x36\x18\xcb\xb2\
+\x76\xac\x12\x48\x98\x8e\x42\x65\x28\x16\x87\xbf\xdf\xdb\xbb\x74\
+\xa6\xe9\x1c\x44\x8d\x86\x05\xc0\x08\x06\x07\x39\x02\xd0\x88\x4a\
+\xab\x04\xb2\x48\xa7\x33\xa6\xa3\xd0\x38\x29\xa5\xa5\xe7\x79\xbf\
+\xe5\xe9\x81\x44\xd1\x62\x01\x30\x82\x53\x4e\xd9\xc2\x02\xa0\x81\
+\x25\x93\x29\x64\xb3\x1d\x90\x92\xff\x04\xea\x41\x18\xfa\xed\xae\
+\xcb\x49\x81\x44\x51\xe2\xac\xa8\x51\xcc\x9f\x7f\x65\x08\x16\x49\
+\x0d\x4d\xa9\x10\x03\x03\xdb\x11\x86\xa1\xe9\x28\x34\x26\x01\xd7\
+\x4d\x7e\x79\xf5\xea\xdc\x17\x4c\x27\x21\x6a\x04\xbc\xb8\x8d\xce\
+\x33\x1d\x80\xe2\x25\x65\x69\x5e\x80\xe3\xb8\xa6\xa3\xd0\x98\x34\
+\x7c\xbf\xf0\xf9\x9e\x9e\xa5\x6f\x34\x9d\x84\xa8\x11\xb0\x00\x18\
+\x85\x10\xc8\x9b\xce\x40\xf1\x13\x42\xa0\xb5\xb5\x8d\xfb\x05\xd4\
+\x01\xad\xb5\xf0\xfd\xe2\xea\x85\x0b\x73\x9c\xc4\x41\x54\x21\x16\
+\x00\xa3\xd0\x1a\x43\xa6\x33\x50\xf5\xa4\xd3\x19\x4e\x0e\xac\x03\
+\x61\x18\x64\xb6\x6d\x53\xbf\x33\x9d\x83\xa8\xde\xb1\x00\x18\x05\
+\x0b\x80\xe6\x93\x4c\xa6\xb8\x69\x50\x1d\xf0\x7d\xef\xa4\x9e\x9e\
+\xc5\x5f\x36\x9d\x83\xa8\x9e\xb1\x00\x18\x85\x10\x18\x36\x9d\x81\
+\xaa\xaf\xb4\x69\x50\x3b\x57\x08\xd4\x34\x8d\x42\xa1\x78\xd1\x9c\
+\x39\xb9\x93\x4c\x27\x21\xaa\x57\xfc\x84\x1b\x1d\x47\x00\x9a\x94\
+\x65\xd9\x68\x6d\x6d\x87\x94\xdc\x39\xb0\x76\x69\xe1\x79\xc1\x2a\
+\x20\xc7\xcf\x31\xa2\x09\xe0\x3f\x9c\xd1\xb1\x00\x68\x62\xa5\x9d\
+\x03\xdb\x61\x59\x3c\x94\xae\x56\x05\x81\x3f\xa9\xbb\x1b\x3f\x33\
+\x9d\x83\xa8\x1e\xb1\x00\x18\x95\xe0\x23\x80\x26\x57\x3a\x51\xb0\
+\x0d\xb6\xed\x98\x8e\x42\x23\x28\x16\x0b\xff\xdc\xdb\xfb\xc5\x2e\
+\xd3\x39\x88\xea\x0d\x0b\x80\x51\x68\xad\x38\x02\x40\x10\x42\xa2\
+\xb5\xb5\x0d\x8e\xc3\x22\xa0\x36\x69\x78\x5e\xfe\xd7\x0b\x17\xe6\
+\xb8\x99\x03\x51\x19\x58\x00\x8c\x42\x08\x3e\x02\xa0\x92\x9d\x7b\
+\x05\xb8\x2e\xaf\x31\xb5\x28\x0c\xc3\xd6\x6d\xdb\xc2\x9b\x4c\xe7\
+\x20\xaa\x27\x2c\x00\x46\xc1\x65\x80\xb4\xbb\xd2\x41\x42\xae\xcb\
+\xd3\x04\x6b\x91\xef\x7b\x5d\x5d\x5d\x8b\xde\x65\x3a\x07\x51\xbd\
+\x60\x01\x30\x0a\x21\x38\x07\x80\x76\x27\x84\x40\x26\xd3\xca\x5d\
+\x03\x6b\x54\x10\x84\x3f\xe2\xa9\x81\x44\xe3\xc3\x02\x60\x14\x7c\
+\x04\x40\x7b\x27\x90\x4e\x67\x90\x4c\xa6\x4d\x07\xa1\x3d\x28\x15\
+\x24\x5d\x17\xbf\x34\x9d\x83\xa8\x1e\xb0\x00\x18\x85\x52\x9a\x23\
+\x00\x34\xa2\x74\x3a\xcd\x91\x80\x1a\xe4\x79\xf9\x73\xe6\xcc\xc9\
+\x9d\x6a\x3a\x07\x51\xad\xe3\x02\xe7\x51\x08\x21\xfb\x01\x6d\x3a\
+\x06\xd5\x2c\x81\x74\xba\x05\x5a\x6b\x14\x8b\x05\xd3\x61\x68\x17\
+\xbe\x1f\xfc\x1a\xc0\x54\xd3\x39\xa8\x36\x74\x77\xe7\x3a\xa5\xb4\
+\x4e\x0d\xc3\xf0\x64\x21\xd4\xa1\x4a\x61\x2a\x80\x49\x5a\xeb\x4e\
+\x40\x25\xb5\x16\x12\x50\xbb\xcc\xf0\x15\xbe\x10\xa2\x20\x84\xc8\
+\x03\x62\x50\x08\xbc\x28\x84\xf5\x90\xd6\xb8\x2f\x9d\xf6\xff\x74\
+\xfd\xf5\x97\x3d\x69\xec\x7f\x26\x42\xdc\xf0\x7c\x14\xf3\xe6\x5d\
+\x71\x8e\x10\xe2\x7a\xd3\x39\xa8\xd6\x69\x0c\x0e\x0e\xc2\xf3\x58\
+\x04\xd4\x92\x44\x22\x75\x55\x5f\x5f\xee\x42\xd3\x39\xa8\x7a\xe6\
+\xcc\xb9\xf8\x40\xa5\x9c\x33\xb5\xc6\x5b\xb4\x0e\x8f\x0b\x43\x3d\
+\x5d\xeb\xb0\x55\x29\x15\xe9\x96\x9e\x52\xca\x50\x4a\xeb\x25\x29\
+\xe5\xdf\x84\x90\xff\x97\x4e\xe3\x47\xcb\x97\xe7\x36\x46\xd9\x47\
+\x35\xb0\x00\x18\xc5\xbc\x79\x57\x9f\x26\x84\x5a\x63\x3a\x07\xd5\
+\x03\x8d\xc1\xc1\x01\x78\x5e\xd1\x74\x10\xda\x41\x4a\xa9\x92\x49\
+\xf9\x9a\x15\x2b\xbe\xb4\xce\x74\x16\x8a\xc7\xdc\xb9\x4b\x4f\xf3\
+\x7d\xf5\xee\x30\x0c\xdf\x1a\x86\xc1\x6b\x94\xd2\x09\x53\xa3\xb6\
+\xb6\x6d\x6f\x91\xd2\xf9\x8b\x10\xe2\x5b\x7d\x7d\x8b\x6f\x31\x12\
+\xa2\x4c\x2c\x00\x46\xb1\x60\xc1\x15\xc7\x69\x2d\x1e\x30\x9d\x83\
+\xea\xc7\xe0\xe0\x76\x78\x9e\x67\x3a\x06\xed\xd0\x9a\xee\x7c\xf1\
+\x8c\x99\x9f\xdb\x75\x7f\x80\x40\x0b\x0c\x40\xa3\x5f\x02\xc3\x1a\
+\x18\x16\x02\x9b\xc2\x10\x2f\x6a\x89\x67\xfa\x1d\x6c\xc8\xe5\x44\
+\x60\x2c\x30\x8d\x68\xde\xbc\xdc\xd4\x7c\x1e\xef\x50\x0a\x67\x29\
+\x15\x9c\x18\x86\xc1\x54\xad\x75\x4d\x5e\xc3\x2c\xcb\x1a\xb6\x2c\
+\xbb\xcf\xb6\xe5\xe7\x57\xac\xc8\x3d\x66\x3a\xcf\x48\x6a\xf2\x37\
+\xaf\x56\x2c\x5c\xf8\x95\x03\xc2\xd0\xe6\xdd\x03\x95\x65\x60\x60\
+\x3b\x7c\x9f\x45\x40\x6d\x10\x78\xd3\x31\xef\xc5\xb4\xf6\xa3\xc7\
+\xfb\x86\x00\xc0\x93\x00\x1e\x82\xc0\x23\x50\xb8\x5f\xb8\xb8\xfd\
+\xfc\x9c\x78\x2e\xbe\x8c\x34\x92\x9e\x9e\x2f\xce\x57\x2a\xfc\x50\
+\x18\x06\x6f\x0c\x43\xbf\xdd\x74\x9e\x89\x70\x1c\x77\xad\x65\xd9\
+\x5f\x58\xb5\x6a\xf1\x2f\x4c\x67\xd9\x13\x0b\x80\x51\xf4\xf6\x5e\
+\x9b\x4d\xa5\xbc\xed\xa6\x73\x50\x7d\xd1\x5a\x63\x60\x60\x3b\x82\
+\xc0\x37\x1d\x85\x00\xa4\x12\xad\xe8\x39\xe9\xe2\x8a\xda\x10\xc0\
+\xb3\x5a\xe0\xcf\x42\xa1\xcf\x73\x71\xf3\x85\x39\xb1\x29\xa2\x78\
+\xb4\x8b\xb9\x73\x73\x93\x3d\x0f\x1f\x50\x4a\xbd\x3b\x08\x82\x63\
+\xb4\x0e\x1b\x66\xa2\xba\x6d\xdb\xfd\x52\xda\xd7\xae\x5e\xbd\xe4\
+\x52\xd3\x59\x76\x62\x01\x30\x2a\x2d\xe6\xcf\xbf\xca\x03\x57\x4b\
+\x50\x99\x58\x04\xd4\x96\xa3\x0f\x3c\x03\x47\xcc\x38\x23\xaa\xe6\
+\x42\x00\x7f\x16\xc0\x72\xcf\xc1\xcf\x58\x0c\x54\xa6\xa7\x27\x77\
+\x9c\x52\xfa\x52\xa5\xc2\xb7\x05\x41\x30\xa9\xd1\x57\x5e\x59\x96\
+\xb3\xcd\x71\xec\x4f\xae\x5a\x95\x33\x7e\x8a\x25\x0b\x80\x31\xcc\
+\x9f\x7f\xe5\x26\x00\x93\x4c\xe7\xa0\xfa\xa3\x94\xc2\xc0\xc0\x36\
+\x84\x61\x68\x3a\x4a\xd3\xb3\x2c\x07\x73\x5e\x7f\x31\x6c\x2b\xf2\
+\x4d\x02\x8b\x02\xb8\x11\x02\xdf\x3b\xff\x32\xf1\x7f\x51\x37\xde\
+\xa8\x76\xcc\xd6\xff\x42\x10\x04\xe7\x04\x81\x3f\xcd\x74\x9e\xea\
+\x13\x70\x1c\xfb\x39\xd7\xb5\xdf\x75\xcb\x2d\xb9\xdb\xcd\xa5\xa0\
+\x51\xcd\x9f\x7f\xe5\x13\x00\x0e\x31\x9d\x83\xea\x53\x18\x86\xe8\
+\xef\xdf\x0a\xad\x1b\xfb\xae\xa6\x1e\xcc\x98\xfa\x5a\xbc\xfe\xb0\
+\x7f\x89\xaf\x03\x81\x3f\x6a\x81\x7f\xff\xf4\x17\xc5\xdd\xf1\x75\
+\x52\xbf\xba\xbb\x73\x9d\x5a\xeb\x0b\xb4\x0e\xdf\xe7\xfb\xfe\x0c\
+\xd3\x79\x6a\x85\xeb\xa6\x56\x7a\x1e\xce\x5e\xb3\x26\x57\xf5\xc9\
+\xa7\x2c\x00\xc6\x30\x7f\xfe\x15\x77\x03\xe2\x24\xd3\x39\xa8\x7e\
+\x85\xa1\x8f\xed\xdb\xb7\x99\x8e\xd1\xf4\x84\x90\xe8\x3e\xe9\xb3\
+\x48\xb9\x1d\x71\x76\xa3\x05\xf0\xeb\x30\xc4\xe7\x2e\xf8\x8a\x58\
+\x1b\x67\x47\xf5\x60\xd6\xac\x9c\x9d\x4e\x8b\xcf\xfa\x7e\xf0\x51\
+\xdf\xf7\x0e\x30\x9d\xa7\x56\xd9\xb6\xbd\xd5\x75\x9d\x73\x57\xac\
+\xc8\xfd\xa1\x9a\xfd\x72\x2b\xe0\x31\x09\x7e\x72\x53\x45\x2c\xcb\
+\x41\x6b\x6b\x16\xac\xb7\xcd\xd2\x5a\xe1\xde\x27\x96\xc5\xdd\x8d\
+\xd0\xc0\x42\x69\xe1\xef\xd7\x5e\xa2\x3f\x12\x77\x67\xb5\xaa\xb7\
+\x77\xe9\xcc\xee\xee\x4b\x6f\x95\xd2\xcb\x0f\x0f\x0f\x5f\xce\x8b\
+\xff\xe8\x82\x20\xe8\xc8\xe7\xf3\x6b\x7a\x7a\x72\xdf\xac\x66\xbf\
+\xfc\x44\x1a\xc3\xfc\xf9\x57\x2e\x03\xf0\x0e\xd3\x39\xa8\xfe\x15\
+\x0a\x79\x0c\x0f\x0f\x9a\x8e\xd1\xd4\x84\x10\x98\x75\xfc\xbf\xa1\
+\xbd\x65\x7a\x75\xfa\x03\x96\x25\x1c\xbc\xef\x23\xb9\xc6\x3f\x59\
+\x74\xd6\xac\x9c\x9d\x48\xe0\x33\x4a\x05\x9f\x0c\x82\x60\x06\x1f\
+\x7b\x4d\x8c\xe3\xb8\x0f\xb7\xb7\x5b\x27\x2f\x5b\x96\x8b\xfd\xc3\
+\x82\x23\x00\x63\x10\x42\x6c\x35\x9d\x81\x1a\x43\x32\x99\xe2\xe1\
+\x41\x86\x69\xad\x71\xff\x53\xd7\x55\xaf\x3f\x60\x61\xc1\xc7\x1f\
+\xae\xfd\x0f\x3d\xa5\x6a\x9d\x56\x59\x6f\xef\xd2\x99\xb3\x67\x2f\
+\x5a\x23\x65\xb1\x50\x2c\xe6\xbf\xea\xfb\x3e\x2f\xfe\x15\xf0\x7d\
+\xef\xa8\xcd\x9b\xfd\x17\x66\xcf\xfe\xd2\x09\x71\xf7\xc5\x02\x60\
+\x0c\x5a\xeb\x97\x4c\x67\xa0\xc6\x91\x4e\xb7\xc0\x75\x79\x5c\xbd\
+\x49\xdb\x06\x5e\xc0\xd6\xc1\x67\xab\xd9\xe5\xeb\xb4\xc4\x6d\x8d\
+\x56\x04\x74\x75\x2d\x7a\xd7\xec\xd9\x97\x3e\x94\xcf\x0f\xfd\xd5\
+\xf7\x8b\xa7\x45\xbd\xdf\x7e\x33\x53\x2a\x68\x0d\xc3\xc1\xbb\xe7\
+\xcc\xc9\xf5\xc4\xd9\x0f\x0b\x80\x31\xb1\x00\xa0\x28\x09\xb4\xb4\
+\xb4\xc2\xb6\x1d\xd3\x41\x9a\x96\xd6\x1a\x0f\xae\xbd\xb1\xda\xdd\
+\xbe\x56\x49\xac\xb8\xfa\x02\x5d\xd7\x43\x40\xb3\x66\xe5\xec\xee\
+\xee\xdc\xe7\xce\x38\xe3\x92\xf5\x9e\xe7\xfd\xd2\xf7\xbd\xa3\x4c\
+\x67\x6a\x54\x4a\x29\x7b\x78\xb8\xb0\x62\xce\x9c\x25\xb1\xcd\x25\
+\x61\x01\x30\xb6\xba\x3b\xe1\x89\x6a\x9b\x10\x40\x6b\x6b\x16\x96\
+\xc5\x1b\x26\x53\xb6\xf6\x3f\x87\xfe\xe1\x17\xab\xda\xa7\x00\x4e\
+\xb2\xd2\xf8\x46\x55\x3b\x8d\xc8\xbc\x79\xb9\xa9\xdd\xdd\x8b\x7f\
+\x25\x65\x71\xb8\x58\xcc\x7f\xb5\xb4\x76\x9f\xc3\xfc\xf1\xd3\x62\
+\x78\x38\xff\x9d\xde\xde\x78\x4e\xb5\x64\x01\x30\x06\xad\x05\x47\
+\x00\x28\x72\x42\x48\x64\x32\x59\xd3\x31\x9a\x96\xd6\x1a\x7f\x5b\
+\x7b\xd3\xd8\x2f\x8c\xde\x07\xaf\xb9\x44\x9f\x6d\xa2\xe3\x89\xe8\
+\xea\xba\xe4\xe0\xee\xee\x4b\x7f\xb7\x75\x6b\x61\x7d\xb1\x58\x78\
+\xa7\x52\x8a\x43\x57\x55\xa7\x91\xcf\x17\xae\xe8\xe9\xc9\x7d\x3c\
+\xea\x96\x59\x00\x8c\x49\x70\x04\x80\x62\x61\x59\x36\x32\x99\x56\
+\xd3\x31\x9a\xd6\x4b\xdb\x9e\xc6\x50\x61\x73\xd5\xfb\x15\x1a\xdf\
+\xfe\x6e\x4e\xa7\xab\xde\x71\x19\xe6\xcc\xc9\x1d\x3e\x7b\xf6\xa2\
+\x35\xbe\x1f\x3c\x59\x2c\x7a\xb3\x4a\xdb\x1b\x90\x39\x1a\x85\x42\
+\xfe\x9b\xdd\xdd\x4b\xde\x1f\x65\xab\x2c\x00\xc6\x20\x84\x64\x01\
+\x40\xb1\x71\xdd\x24\x57\x06\x18\x62\x68\x2e\x00\x00\x4c\x2f\xf8\
+\xf8\x37\x13\x1d\x8f\xe5\xcc\x33\x97\xbe\x6e\xf6\xec\x4b\xee\x1b\
+\x1e\xce\x3f\xea\xfb\xc5\xd3\x6a\xf5\xb8\xdd\x26\x25\x3c\x2f\xff\
+\xff\x9d\x75\xd6\x92\xb9\x51\x35\xc8\x02\x60\x0c\x5b\xb6\x6c\x7f\
+\x09\x7c\xd8\x45\x31\x4a\xa7\x33\x70\x1c\xd7\x74\x8c\xa6\xb4\x61\
+\xcb\xe3\x28\xf8\x46\x0e\xfc\xfc\xf4\x77\xcf\xd3\x35\x33\x9c\x7e\
+\xe6\x99\xb9\x37\xcd\x9e\xbd\xe8\x1f\x43\x43\xc3\xf7\xf8\xbe\x1f\
+\xfb\xf2\x33\x9a\x18\xad\xb5\x18\x1a\x2a\xfc\x66\xce\x9c\xdc\xe1\
+\x51\xb4\xc7\x02\x60\x0c\x3b\xf6\x67\xe6\x5e\x00\x14\xab\x4c\xa6\
+\x15\x52\xf2\x9f\x63\xb5\x69\xad\xf0\x8f\x75\x2b\x4c\x74\xbd\x6f\
+\x7e\x0a\x8c\xcf\x05\x98\x33\x27\x77\x78\x57\xd7\xa2\x3b\x86\x86\
+\xf2\x7f\xf6\xfd\xe2\xd1\xbc\xd7\xa9\x7d\x5a\x2b\xc7\xf3\xfc\xbb\
+\x7b\x7b\x73\x15\x4f\x22\xe2\x31\xb7\xe3\xa0\x35\x5e\x12\x02\x9d\
+\xa6\x73\x50\xe3\x12\x42\xa2\xb5\xb5\x0d\xdb\xb7\xb3\xd6\xac\xb6\
+\x17\x36\x3d\x84\x99\x87\x6a\xc8\x2a\x6f\x8c\x2a\x04\xde\x01\xe0\
+\x37\x55\xed\x74\x87\xae\xae\x4b\x0e\x06\xe4\xcf\x86\x87\x0b\x6f\
+\xe2\x45\xbf\xfe\x04\x41\x90\x95\x52\xdc\x05\xe0\xc8\x4a\xda\xe1\
+\x2d\xc7\xb8\x70\x22\x20\xc5\xcf\xb2\x6c\xb4\xb4\x70\x52\x60\xb5\
+\x05\xa1\x8f\xb5\xeb\x0d\x9c\xc8\xaa\xd1\x93\xcb\xe9\xaa\xde\x84\
+\xcd\x9d\x9b\x9b\xdc\xd5\x95\x5b\xe1\xfb\xc1\x93\x9e\x57\xe4\xc5\
+\xbf\x8e\x79\x9e\x7f\x44\x77\x77\xee\xbf\x2a\x69\x83\x05\xc0\x38\
+\x08\xa1\x58\x00\x50\x55\x24\x12\x9c\x14\x68\xc2\x93\x2f\xfe\xd9\
+\x44\xb7\xed\xed\x1e\x8e\xae\x46\x47\xb3\x66\xe5\x92\xdd\xdd\xb9\
+\x9f\x0f\x0d\x15\x36\x78\x5e\xbe\x97\x93\xfb\x1a\x83\xe7\x15\x3e\
+\xd2\xd3\xb3\xe4\xf4\x89\xbe\x9f\x05\xc0\xf8\xb0\x00\xa0\xaa\x49\
+\xa5\x5a\xb8\x53\x60\x95\x0d\x0e\x6f\xc1\xf6\xa1\xe7\xab\xde\xaf\
+\x10\x98\x19\x77\x1f\xdd\xdd\x8b\x97\x58\x96\xb7\xad\x58\xcc\xff\
+\xb3\x52\x9a\x9f\xf9\x0d\x44\x6b\x2d\x7c\xdf\xbb\x61\xe1\xc2\x5c\
+\x66\x22\xef\xe7\x5f\x86\x71\x11\x2f\x98\x4e\x40\xcd\x43\x08\x81\
+\x4c\x26\x0b\x21\xf8\xcf\xb3\x9a\x1e\x79\xfe\xb6\xea\x77\x2a\x70\
+\x58\x5c\x4d\x9f\x75\xd6\x92\xb9\x67\x9c\x71\xf1\xc6\x62\xb1\xb0\
+\x28\x0c\xc3\x44\x5c\xfd\x90\x59\x61\x18\xb4\xf4\xf7\x87\x13\xda\
+\xd5\x8a\x9f\x30\xe3\xa0\xb5\xae\xfe\xad\x01\x35\x35\x29\xe5\x8e\
+\x4d\x82\x38\x52\x5b\x2d\xdb\x07\xd7\x57\xbf\x53\x8d\x7d\xa2\x6e\
+\xb2\xb4\x96\xff\xd2\xc7\x07\x07\x87\x6f\x0c\x82\xa0\xa1\x0e\x20\
+\xa2\xbd\x2b\x16\xfd\x59\x13\xd9\x1f\x80\x05\xc0\x38\x48\xc9\x11\
+\x00\xaa\x3e\xc7\x71\x91\x4c\xf2\xe4\xc0\x6a\x39\xfa\xc0\xae\xaa\
+\xf7\x29\x34\x22\xbb\x40\xcf\x9d\x9b\x4b\x77\x75\x2d\xba\x6e\x78\
+\x78\xf8\x6e\xdf\xf7\x0e\x8d\xaa\x5d\xaa\x07\x1a\xf9\xbc\xf7\xf3\
+\x59\xb3\x72\x65\x4d\x2a\x65\x01\x30\x0e\x4a\x71\x04\x80\xcc\x28\
+\xcd\x07\xe0\x6a\xdd\xb8\x75\x64\xa7\x63\xc6\xa4\xea\xef\x7f\xa3\
+\x45\x34\x9f\xc1\x3d\x3d\x4b\x16\x0f\x0d\x15\xb7\x79\x5e\x71\x1e\
+\x27\xf8\x35\xa7\x30\x0c\x32\xc9\x24\x7e\x54\xce\x7b\x58\x00\x8c\
+\x83\x6d\x5b\x1c\x01\x20\x23\x84\x10\x68\x69\xe1\x7c\x80\x38\x49\
+\x29\x71\xd2\x61\xef\x36\x1d\x63\x42\xba\xbb\x17\xbd\x6d\xf6\xec\
+\x4b\x9e\x2d\x14\x86\x73\x3c\xa8\x87\x3c\xaf\xf8\xcf\x67\x9d\x75\
+\xf5\xf4\xf1\xbe\x9e\x9f\x2a\xe3\xb0\x6c\xd9\x67\xb6\x00\xc8\x9b\
+\xce\x41\xcd\xc9\xb2\x2c\xb4\xb4\xb4\x98\x8e\xd1\xb0\x0e\x98\x7a\
+\x02\x32\xc9\x49\x46\xfa\x16\x13\xfc\x5c\xe9\xed\xcd\x65\x67\xcf\
+\x5e\xb4\xa6\x58\xf4\x7e\xeb\xfb\xfe\x8c\xa8\x73\x51\x7d\x52\x4a\
+\xc9\x62\x71\xdb\xaf\xc6\xfb\x7a\x16\x00\xe3\xc7\x51\x00\x32\xc6\
+\x75\x93\x48\x24\x38\x91\x3b\x6a\xae\x93\xc6\xf1\x87\x2c\x30\x19\
+\x61\x43\xb9\x6f\xe8\xe9\xc9\x7d\xbc\x58\x2c\x6e\xf4\xfd\xe2\x69\
+\xdc\xc8\x87\xf6\x14\x04\xde\x9b\xbb\xba\x96\x9e\x32\x9e\xd7\xf2\
+\xe1\xe2\xf8\x3d\x0f\xe0\x10\xd3\x21\xa8\x79\xa5\xd3\xad\xf0\xfd\
+\x00\x4a\x85\xa6\xa3\x34\x8c\x93\x0e\x7f\x27\x24\x2c\x63\xfd\x6b\
+\x8d\x4d\xe3\x7d\x6d\x69\xfb\x5e\xac\x2c\x14\x0a\x47\xf0\xc2\x4f\
+\x23\xd1\x5a\x03\xf0\x7e\x8c\x71\x6c\x13\xcc\x11\x80\xf1\xe3\x08\
+\x00\x19\x55\x9a\x0f\xc0\xa5\x81\x51\xd9\x77\xf2\x11\x98\xd6\x5e\
+\xd1\x56\xea\x15\x13\x02\x8f\x8d\xe7\x75\x5d\x5d\x8b\xbf\x18\x04\
+\xc1\xe3\x9e\xe7\xf3\xe2\x4f\x63\xf2\xfd\xe0\x88\xb9\x73\x73\x6f\
+\x18\xeb\x75\x1c\x01\x18\x3f\xae\x04\x20\xe3\x1c\xc7\x41\x32\x99\
+\x44\xa1\xc0\x29\x29\x95\x70\x6c\x17\xaf\x3f\xec\x5f\x4c\xc7\x40\
+\x20\xf1\xe0\x68\xdf\x3f\xf3\xcc\xa5\xaf\xf3\x3c\xef\x46\xcf\x2b\
+\xec\x57\xad\x4c\x54\xff\xb4\xd6\x28\x14\xd4\xb7\x01\x9c\x38\xda\
+\xeb\x38\x02\x30\x4e\x5a\xb3\x00\xa0\xda\x90\x4e\xb7\xc0\xb2\x58\
+\xbb\x4f\x94\x10\x02\x33\x0f\x7b\x07\x2c\xe9\x9a\x8e\x52\x6c\xd9\
+\xb0\xf7\x11\x80\x59\xb3\x72\x76\x4f\x4f\xee\xa7\xa5\x35\xfd\x3e\
+\x2f\xfe\x54\x36\xdf\x2f\xce\xec\xea\xba\x7c\xd4\x21\x2e\x16\x00\
+\xe3\x24\xa5\x78\xc6\x74\x06\xa2\x12\x81\x4c\xa6\x15\x42\xf0\x51\
+\xc0\x44\xec\x37\xf9\x28\x4c\xef\x3c\xce\x74\x0c\x00\x78\xe8\x23\
+\xdf\x13\xfe\x9e\x5f\xec\xee\x5e\x72\xa6\x65\x79\xdb\x0a\x85\xfc\
+\x7b\xb8\xa6\x9f\x2a\xa1\x75\xe1\x3b\xa3\x7d\x9f\x05\xc0\x38\x85\
+\xa1\x5e\x6b\x3a\x03\xd1\x4e\x96\x65\x23\x99\x4c\x9b\x8e\x51\x77\
+\x12\x6e\x0b\x4e\x3a\xdc\xfc\xd0\xff\x0e\x7f\xdd\xfd\x97\x39\xd9\
+\xd3\x93\xfb\x69\xb1\x98\xbf\x39\x0c\x43\xae\xfb\xa4\x8a\x85\xa1\
+\xf7\xd6\xb9\x73\x73\x23\x7e\x50\x70\x1c\x71\x9c\xc2\x10\xeb\x24\
+\xcb\x25\xaa\x21\xa9\x54\x1a\x9e\x57\x44\x18\x06\xa6\xa3\xd4\x05\
+\x21\x04\xde\x70\xe4\x7b\x8c\xce\xfa\xdf\x95\x06\xfa\x76\xfe\xbc\
+\xa7\xe7\xb2\xb7\xf8\x7e\xfe\xa6\x42\x21\x68\x37\x99\x89\x1a\x8b\
+\x52\x5a\x7a\x1e\x16\x01\xf8\xfc\xde\xbe\xcf\x4b\xda\x38\xdd\x74\
+\xd3\x85\x9b\x00\x0c\x99\xce\x41\xb4\xab\x96\x16\x3e\x0a\x18\xaf\
+\x43\xa7\xbf\x05\x9d\xad\x07\x9b\x8e\xb1\x53\xa8\x1c\xdc\xf6\xca\
+\x5d\xff\xc0\x1f\xc2\x90\x17\x7f\x8a\x5e\x10\x04\x1f\x1c\xe9\x7b\
+\x2c\x00\xca\xa2\x39\x0f\x80\x6a\x8a\x6d\xdb\x48\x26\x53\xa6\x63\
+\xd4\xbc\x8e\xec\x74\x1c\x7b\xe0\x99\xa6\x63\xbc\x4c\x08\xdc\xb5\
+\xf2\xcf\x97\x1f\x70\xfa\xe9\xc1\x86\xd2\xb3\x7e\xae\xed\xa4\x78\
+\x84\xa1\x3f\x79\xce\x9c\xdc\xa9\x7b\xfb\x1e\x0b\x80\xf2\xac\x33\
+\x1d\x80\x68\x4f\xa9\x54\x0b\x2c\xab\x36\x86\xb5\x6b\x91\x63\x27\
+\xf1\xe6\xa3\x3f\x64\x3a\xc6\x6e\xd6\x6f\x7d\xd4\x0a\xc3\xc1\x7b\
+\xc3\xd0\x9f\x6c\x3a\x0b\x35\xbe\x20\x50\x97\xec\xed\xeb\x2c\x00\
+\xca\xc3\x02\x80\x6a\x52\x69\x83\x20\xda\x93\x10\x02\x6f\x38\xea\
+\x3d\x70\xac\xda\x1a\x25\x49\x14\x67\x9c\xac\x94\xe2\xe7\x2f\x55\
+\x45\x10\x84\x6f\xdd\xdb\xd7\xf9\x17\xb0\x0c\x42\x88\xb5\xa6\x33\
+\x10\xed\x8d\x6d\x3b\x48\x24\x92\xa6\x63\xd4\x18\x81\x23\x0f\x78\
+\x3b\x26\x67\x0f\x35\x1d\x64\x37\x61\x11\x10\x7e\x0b\xa6\xb7\x8f\
+\xba\x47\x0b\x51\x64\x94\x0a\x92\x67\x9d\xb5\x64\xee\x9e\x5f\x67\
+\x01\x50\x1e\x8e\x00\x50\xcd\x4a\xa7\x33\x90\x5c\xaa\xf2\xb2\x7d\
+\x26\x1d\x8e\x23\x67\xcc\x36\x1d\xe3\x55\xbc\x1d\x53\x89\x0f\xe9\
+\xec\x36\x1b\x84\x9a\x4a\xb1\x18\xfe\xfb\x9e\x5f\xe3\xa7\x45\x19\
+\x94\xe2\x5e\x00\xe3\xa5\xb5\xda\x0e\x80\xeb\xd3\xaa\xa8\x74\x56\
+\x40\xc6\x74\x8c\x9a\xd0\x9a\xee\xc4\x29\x47\xbc\xcf\x74\x8c\x57\
+\xd1\x0a\xf0\x76\xec\xe2\x6c\x87\x6d\x98\x96\x3d\xc6\x6c\x20\x6a\
+\x1a\x61\x18\xbe\xea\x84\x40\x16\x00\xe5\x79\xd2\x74\x80\x7a\xe1\
+\xfb\xfe\x76\x40\xdf\x6f\x3a\x47\xb3\x71\x9c\x04\x1c\xa7\xb9\x8f\
+\x0d\x76\x9c\x24\x4e\x7d\xed\x27\x20\x6b\x70\x79\xa4\x3f\x8c\xdd\
+\xce\xf2\x39\x72\xf2\x7c\x63\x59\xa8\xb9\x28\x15\x26\x7b\x7b\x97\
+\xce\xdc\xf5\x6b\x2c\x00\xca\xb0\x7c\xf9\x67\x37\x02\xd8\x6e\x3a\
+\x47\x3d\xf0\x7d\xcf\x16\x42\xfc\xd1\x74\x8e\x66\xd4\xd2\xd2\xbc\
+\x9b\xc8\x49\x69\xe1\xcd\xc7\x7c\x10\xae\x5d\x9b\xbf\x07\xde\xe0\
+\xee\xbf\xb6\xc2\x16\x1c\x32\xf9\x74\x33\x61\xa8\xc9\x68\x84\xa1\
+\xfa\xc4\xae\x5f\x61\x01\x50\x26\x21\xf0\x84\xe9\x0c\xb5\x4e\xa9\
+\x10\x4a\x85\x96\xd6\x9a\x05\x80\x01\x52\x5a\x48\xa5\x6a\xf3\x02\
+\x18\x27\x21\x04\x4e\x3c\x6c\x01\x3a\x5a\xf6\x37\x1d\x65\xaf\xfc\
+\x61\x60\x6f\x9b\x36\x1e\x98\x7d\x1b\x2c\x61\xfc\x60\x22\x6a\x02\
+\x5a\x87\xbb\x4d\x8a\x61\x01\x50\x26\xad\x59\x00\x8c\xa5\x58\x2c\
+\x00\xc0\xb0\xef\x8b\x3f\x82\x87\x97\x1b\x91\x4a\xa5\x9b\x6c\x6f\
+\x00\x81\xa3\x0e\x38\x1d\xfb\x4f\xae\xdd\x99\xf5\x85\xfe\x11\xbe\
+\x11\xda\x38\x61\xc6\x7b\xab\x9a\x85\x9a\x53\x10\xf8\xfb\xcf\x9a\
+\x95\x7b\xf9\x08\x00\x16\x00\xe5\x7b\xdc\x74\x80\x5a\xe7\x79\x45\
+\x08\x21\x07\x76\x6c\x9f\xfc\xa8\xe9\x3c\xcd\x2a\x9d\x6e\x9e\x09\
+\x81\x07\xed\x33\x13\x47\xcc\x38\xc3\x74\x8c\x11\x79\xc3\x80\x1a\
+\x65\x4a\x6c\x9b\x75\x18\xa6\x64\x8f\xaa\x5e\x20\x6a\x4a\x5a\x6b\
+\x91\x4a\x59\x67\xed\xfc\x35\x0b\x80\x32\x69\x2d\x58\x00\x8c\x22\
+\x0c\x03\x84\x61\x08\xad\xd1\x0f\x00\x9c\x07\x60\x8e\xe3\xb8\x70\
+\xdd\xc6\x9f\x10\x38\xad\xf3\x30\xcc\x3c\xe4\x9d\xa6\x63\x8c\x4c\
+\x03\xc5\x91\xee\xfe\x77\x79\xcd\xb1\x93\xff\x09\xfc\x48\xa6\xb8\
+\x05\x81\xff\xf2\xcc\x53\xfe\x6d\x2b\x93\x65\xf1\x11\xc0\x68\x3c\
+\xaf\x08\x00\x10\x42\x6e\x05\x00\xce\x03\x30\x2b\x9d\xce\x34\xf4\
+\x61\x41\x9d\xd9\xe9\x78\xe3\x51\x1f\x30\x1d\x63\x54\xde\xe0\xe8\
+\x77\xff\x3b\x89\x30\x81\x99\xd3\xdf\x13\x7f\x20\x6a\x72\xfa\x0d\
+\x3b\x7f\xc6\x02\xa0\x4c\x42\x38\x1c\x01\x18\x91\x46\xb1\x58\x2a\
+\x00\xa4\x54\x5b\x00\x40\x29\x8b\x05\x80\x41\x52\x4a\x24\x93\x23\
+\x1e\x07\x5e\xd7\x32\xe9\x49\x78\xeb\x6b\x3f\x0e\x51\xc3\xe7\xe8\
+\x68\x05\x14\x06\xc6\xff\xfa\x0e\xfb\x68\xec\xd7\x76\x42\x7c\x81\
+\xa8\xe9\x29\x15\x1e\xb8\xf3\xe7\x2c\x00\xca\xb4\x6c\xd9\xf9\x2f\
+\x81\x4b\x01\xf7\x2a\x08\x02\x28\x15\xee\xf8\x95\x7c\x09\x00\xae\
+\xbf\xfe\x82\xb5\x00\x9e\x35\x16\x8a\x90\x4c\xa6\x1a\x6e\x87\xc0\
+\x54\x32\x8b\xd3\x8f\xff\x14\x24\x6a\x7b\xa2\x63\x7e\x5b\xa9\x08\
+\x28\xc7\x51\x93\xdf\x51\x73\x67\x17\x50\xe3\x08\x43\xe5\xce\x99\
+\x73\xf1\x81\x00\x0b\x80\x09\xd2\x1c\x05\xd8\x8b\x1d\xb3\xff\x01\
+\x00\x5a\xe3\xa5\x57\x7e\xae\x7f\x6f\x24\x10\x01\x28\x2d\x8f\x6b\
+\xa4\x65\x81\xa9\x44\x16\xa7\x9f\x70\x01\xa4\xac\xed\xa5\x73\x61\
+\x71\xc7\xc6\x3f\x65\xd2\x81\x8d\x53\xf6\xff\x78\xf4\x81\x88\x00\
+\x94\x16\x66\x25\x7a\x01\x16\x00\x13\x24\x38\x0f\x60\x0f\x5a\xbf\
+\x32\xfc\x0f\x00\x42\xe0\x85\x5d\xbe\xfd\xdb\xea\x27\xa2\x5d\x25\
+\x12\x09\xd8\xb6\x3d\xf6\x0b\x6b\x5c\x32\x91\xc1\xdb\x8e\xff\x54\
+\x5d\xdc\x21\x0f\x6f\x9b\xf8\x7b\x5d\x3d\x05\x47\xed\x73\x6e\x74\
+\x61\x88\x76\xa1\x94\x7a\x0b\xc0\x02\x60\xa2\x58\x00\xec\xa1\x34\
+\xf9\xef\x24\x7e\x6f\x03\x00\x00\x20\x00\x49\x44\x41\x54\x95\x25\
+\xff\x42\xc8\x7f\xec\xfc\xb9\x6d\x87\xb7\x99\xc8\x44\xbb\x12\x48\
+\xa7\x5b\x81\x1a\x7e\x5e\x3e\x96\x64\xa2\x05\x6f\x3f\xfe\x02\x24\
+\x9c\xda\x1f\xcd\x28\x6c\x07\x94\x5f\x59\x1b\xfb\x26\xdf\x80\x7d\
+\xdb\x8f\x8f\x26\x10\xd1\x2e\x94\x0a\x8f\x05\x58\x00\x4c\x08\x97\
+\x02\xbe\x5a\xb1\x98\xdf\xe5\x57\x02\x99\x8c\x7a\xb9\x00\x58\xb6\
+\xec\xf3\xcf\x00\x78\xba\xfa\xa9\x68\x57\xb6\x6d\x23\x91\xa8\xed\
+\x61\xf3\x91\x24\x13\x19\x9c\x7e\x42\x7d\x5c\xfc\x83\x22\x50\x2c\
+\x63\xe2\xdf\x88\x34\x70\x74\xe7\x3b\x91\x4e\x4c\x8a\xa0\x31\xa2\
+\x57\x28\xa5\x0e\x00\x58\x00\x4c\x08\x97\x02\xee\x2e\x0c\x43\x04\
+\x41\xf8\xf2\xaf\x85\x10\xe1\xb2\x65\x39\x6f\xf7\x57\x09\x3e\x06\
+\xa8\x01\xa5\xb9\x00\xf5\x35\x0a\x90\x4a\xb4\xe2\xed\xc7\x7f\x0a\
+\xae\x5d\xfb\x1b\x1b\x69\x05\xe4\xb7\x44\xd8\x5e\x68\xe1\xe4\x19\
+\x9f\x80\x14\xf5\xff\xf8\x86\x6a\x87\x52\xaa\x0d\x60\x01\x30\x21\
+\x5c\x0a\xb8\xbb\xd2\xdd\xff\x2b\xc3\xff\x52\x8a\xc2\x9e\xaf\xd1\
+\x5a\xff\xae\x9a\x99\x68\xef\xa4\xb4\x90\x4c\x26\x4d\xc7\x18\xb7\
+\x4c\xba\x13\x67\xcc\xfc\x77\x24\x9c\x56\xd3\x51\xc6\xa5\xb0\x0d\
+\x50\xe1\xd8\xaf\x2b\x87\x0c\xd2\x38\xe5\xc0\x4f\x8c\xfd\x42\xa2\
+\x71\x52\x4a\xcb\xee\xee\x5c\x27\x0b\x80\x09\xd8\xb1\x14\xb0\x82\
+\x29\x3e\x8d\x65\xd7\xc9\x7f\x00\x20\xa5\x7c\xd5\xbe\x67\x42\x58\
+\xbf\x05\xcf\x05\xa8\x09\xa9\x54\x4b\x5d\x6c\x0e\xd4\x99\x9d\x8e\
+\x33\x4e\xb8\x10\xb6\x55\x1f\x05\x8b\x37\x58\xda\xf2\x37\x0e\x29\
+\xbd\x2f\x4e\x98\xfe\xee\x78\x1a\xa7\x26\xa4\xa1\xb5\x7a\x1d\x0b\
+\x80\x09\xd3\x7c\x0c\x80\xd2\xd2\x3f\xfd\xaa\x85\xce\x62\xd3\x9e\
+\xaf\xbb\xee\xba\x0b\x5e\x04\xcf\x05\xa8\x09\x42\x88\x9a\xdf\x1c\
+\x68\x6a\xc7\x21\x38\xed\xb5\x9f\x84\x10\xf5\xf1\x11\x15\x78\x40\
+\x3e\xe6\xdd\x41\x3a\xed\xe3\x70\xe8\xd4\xd9\x63\xbf\x90\x68\x1c\
+\x84\x90\x33\xeb\xe3\x5f\x57\x4d\x92\x8f\x99\x4e\x50\x0b\x0a\x85\
+\xfc\xab\xbe\x26\x84\x58\x3f\xc2\xcb\x39\x0f\xa0\x46\xd4\xee\xe6\
+\x40\x02\xfb\x4f\x3d\x1e\x6f\x3e\xfa\xc3\xa6\x83\x8c\x9b\x0e\x81\
+\xfc\x66\x54\x65\x7c\xeb\xc0\xf4\xe9\x98\xd1\x7e\x52\xfc\x1d\x51\
+\xc3\x93\x12\x47\xd6\xe2\x27\x40\xbd\x78\xc4\x74\x00\xd3\x82\xc0\
+\x47\xb8\x97\x03\xce\x85\x10\xeb\x46\x78\x0b\xe7\x01\xd4\x88\x5a\
+\xdd\x1c\xe8\xd0\x19\x6f\xc4\x49\x87\xfd\xb3\xe9\x18\x65\x19\xda\
+\x12\xfd\x73\xff\x91\x68\x0d\x1c\xd1\xb1\x00\xd3\xda\x8e\xa9\x4e\
+\x87\xd4\xb0\x94\x0a\x0f\x66\x01\x30\x61\xfa\x61\xd3\x09\x4c\xdb\
+\xdb\xdd\x7f\x89\xdc\xeb\xe3\x11\xad\xbd\xdf\x01\xa8\xd2\x47\x25\
+\x8d\x25\x91\x48\xc0\xb2\x6a\x65\x2b\x5d\x81\xa3\x0f\x3a\x03\xaf\
+\x3d\xf0\x6c\xd3\x41\xca\x32\xbc\xa5\xb4\xe3\x5f\x35\x69\x25\x70\
+\xec\xa4\x7f\x41\x67\xcb\x41\xd5\xed\x98\x1a\x8a\xd6\x82\x93\x00\
+\x27\x4a\x08\xd9\xd4\x05\x80\x52\x0a\xbe\xef\xed\xf5\x7b\x52\xe2\
+\xa1\xbd\x7d\x7d\xf9\xf2\x2f\x6c\x06\x70\x4f\x9c\xb9\xa8\x1c\xb5\
+\x31\x0a\x20\xa5\x85\x93\x8e\x58\x88\x23\xa6\x9f\x61\x3a\x4a\x59\
+\x0a\xdb\x27\xb6\xd5\x6f\x14\xa4\x94\x38\xf9\x88\x77\x23\x9d\xe8\
+\x30\x13\x80\xea\x9e\xd6\x3a\xcb\x02\x60\x82\x86\x87\xed\x27\x00\
+\x8c\xe3\x90\xcf\xc6\x54\x28\xe4\xa1\xf5\xde\x1f\x7a\xba\xae\x75\
+\xff\x48\xef\xd3\x1a\x7d\xb1\x85\xa2\xb2\x39\x4e\x02\x96\x65\x6e\
+\x8d\xb9\xeb\x24\x70\xda\x71\x1f\xc5\xfe\x93\x4f\x34\x96\x61\x22\
+\xbc\xa1\x88\x36\xfb\x99\x00\x2b\x01\xb4\x4c\x05\x52\xa9\x2c\xde\
+\x72\xec\x87\x90\x74\xeb\x63\x89\x24\xd5\x1a\xdd\xc2\x02\x60\x82\
+\x56\xae\x3c\xbf\x88\x26\xdd\xdd\xae\xb4\xef\xff\xde\x87\xff\x85\
+\x90\xea\x86\x1b\x2e\x19\xf1\xf4\x3f\x21\xd4\xea\xd8\x82\x51\xd9\
+\x84\x00\x52\x29\x33\x2b\x02\xd2\xc9\x36\x9c\x7e\xc2\x85\x68\x6f\
+\xd9\xdf\x48\xff\x13\x15\xe4\x4b\xa7\xfc\x99\xe0\x24\x81\xcc\xe4\
+\xd2\x9f\x1b\x00\xb4\x24\x27\xe1\x4d\x47\x7f\x10\xae\x5d\xdb\xab\
+\x3a\xa8\xf6\x28\xa5\x53\x2c\x00\x2a\xd3\x94\x8f\x01\x8a\xc5\x91\
+\xef\xfe\x2d\x4b\x0e\x8e\xf6\x5e\xcb\x3a\xe8\x4e\x00\x11\xee\x95\
+\x46\x95\x72\x5d\xb7\xea\x07\x05\x4d\x6a\x3b\x10\x5d\x27\x5e\x54\
+\x77\x77\xaf\x41\xb1\x34\xe9\xcf\xc4\x8e\x16\x4e\x0a\x48\x4f\xc6\
+\xab\x36\x72\x6c\x6b\xd9\x07\x6f\x3a\xfa\x03\xb0\xad\x44\xf5\x43\
+\x51\xdd\xd2\x5a\xbb\x2c\x00\x2a\x20\x84\x68\xba\x02\x40\x6b\x3d\
+\xca\xe4\x3f\x00\x90\x23\x2d\x01\x04\x00\x2c\x5b\xf6\xce\x10\xe0\
+\xae\x80\xb5\x45\x54\x71\x14\x40\xe0\xb0\x19\x6f\xc2\xa9\xc7\x7e\
+\xac\x6e\xd6\xf8\xef\x14\x16\x81\xa1\x4d\x30\x72\xf1\x77\x5b\x81\
+\xf4\x28\x47\x02\x74\xb4\xce\xc0\x29\x47\xfe\x4b\xdd\xfd\x9e\x92\
+\x49\xda\xe2\xdf\x96\x8a\x34\xdf\x4a\x00\xcf\x2b\x42\xa9\x3d\x37\
+\xfe\x79\x85\x65\x89\x31\x1f\x8b\x70\x1e\x40\xed\x29\xcd\x05\x70\
+\x62\xed\x43\x4a\x0b\xaf\x3b\x7c\x01\x8e\xad\xb3\x99\xfe\x00\x10\
+\x7a\xc0\xa0\x81\x8b\xbf\x10\x40\xaa\x13\x48\xb5\x8d\xfd\xda\xa9\
+\xed\x87\xe3\xd8\x83\x7a\xe3\x0f\x45\x0d\x42\xb3\x5c\xac\x44\x18\
+\x36\xd7\x4a\x00\xad\x81\x42\x61\xf4\x69\xcf\x42\xc8\x07\xc7\x6a\
+\xc7\xb6\x43\x16\x00\x35\x28\xce\x51\x00\xd7\x49\xe2\xb4\xe3\x3e\
+\x8e\x03\xa6\xd4\xdf\x26\x36\xa1\x67\xe6\xce\x5f\x5a\x40\xcb\x14\
+\xc0\x2d\xe3\x8f\xe5\x90\x7d\xdf\x82\x8e\xcc\x8c\xf8\x42\x51\xc3\
+\x50\x0a\x2c\x00\x2a\x51\x2c\xda\x8f\xa0\x89\xf6\xb7\xf7\xfd\x22\
+\xc2\x70\xf4\x65\xfc\x42\x58\xb7\x8f\xd5\xce\x8e\xe3\x81\x9b\x7e\
+\x23\xa5\x5a\xe3\xba\x4e\x2c\x2b\x02\xda\x32\xd3\x30\xfb\xc4\xcf\
+\xa1\xbd\x65\x7a\xe4\x6d\xc7\x6d\xe7\xc5\xff\x55\xbb\x5d\xc7\x6c\
+\xe7\x4c\x7f\xab\xcc\xd3\x9b\x85\x10\x38\xe6\xa0\x9e\x78\x42\x51\
+\x43\x11\x42\xf3\x34\xc0\x4a\xac\x5c\x79\x7e\x3f\x80\x17\x4d\xe7\
+\xa8\x0e\x8d\x7c\x7e\xec\x45\xcf\x4a\x85\x7f\x18\x57\x6b\x7c\x0c\
+\x50\x83\xa2\x9d\x0b\x20\x84\xc0\x6b\xf6\x7b\x03\xde\x7e\xfc\x05\
+\x75\x39\x4b\x3d\x28\x02\x83\x2f\x55\xf9\xe2\x2f\x80\x44\x2b\x90\
+\x99\x52\x1a\x01\x98\x88\x29\x6d\x87\xa2\x35\x35\x25\xda\x5c\xd4\
+\x70\xb4\xe6\x08\x40\x14\xf6\xba\xe9\x4d\xa3\xf1\x7d\x6f\xaf\xdb\
+\xfe\xee\x4a\x4a\x2b\xe8\xeb\xcb\x8d\x73\x86\xbf\x5c\x15\x41\x2c\
+\x8a\x58\x69\x2e\x40\xe5\xbb\x03\xda\xb6\x8b\x37\x1e\xfd\xaf\x38\
+\xfe\xe0\x73\x23\x48\x55\x7d\x41\xa1\xfa\xc3\xfe\x96\x5d\xba\xf0\
+\x27\xc7\xf1\xbc\x7f\x2c\xfb\x4f\x9d\x59\x79\x23\xd4\xf0\x58\x00\
+\x54\x4c\x34\xc5\x50\x76\x3e\x3f\xda\xcc\xff\x12\x29\xe5\xb8\xcf\
+\x43\x2b\x14\xec\xdf\x01\x30\xb4\x95\x0a\x8d\x44\x08\x54\x7c\x52\
+\x60\x5b\x66\x1a\x7a\x4e\xba\x08\xd3\xda\x8f\x8c\x28\x55\x75\xf9\
+\xc3\xd5\xbf\xf8\x27\x5a\x81\xcc\x3e\xe5\x0f\xf9\x8f\x64\x4a\xdb\
+\xa1\xd1\x34\x44\x0d\x8d\x05\x40\xc5\x1a\x7f\x25\x80\xe7\x79\x08\
+\x02\x7f\xcc\xd7\x09\x21\xc7\xfd\x38\x64\xc7\x46\x4a\xb7\x55\x92\
+\x8b\xe2\x91\x48\x24\x20\x27\x30\xfe\x2c\x84\xc0\x41\xfb\x9e\x84\
+\xb7\x1f\x7f\x01\x1c\xcb\xfc\x16\xc3\x13\x51\xec\x2f\xed\xef\x5f\
+\x2d\xd2\x89\xee\xae\x7f\x57\xed\x99\xfd\x60\x49\x73\x3b\x3c\x52\
+\xed\x13\x42\x68\x16\x00\x15\x92\x52\x34\xf4\x19\xf7\x5a\x03\xf9\
+\xfc\xd0\xb8\x5e\x6b\x59\x72\xc4\x2d\x80\xf7\xde\xb6\xbe\x71\x42\
+\xa1\x28\x66\xe5\xcf\x05\xb0\x2d\x07\xa7\x1c\xf5\x5e\xcc\x7c\xcd\
+\x3b\x62\xca\x14\x33\x0d\xe4\xb7\x00\x85\xfe\xea\x74\x27\x24\x90\
+\xc8\x02\xad\xd3\x4a\x13\xfe\xa2\x26\x85\x8d\x96\xe4\x28\x1b\x07\
+\x50\xd3\x13\x02\x9a\x25\x62\x85\x94\x0a\x1e\x05\x6a\xe5\x44\xb5\
+\xe8\x79\x5e\x61\xcc\x67\xff\x3b\x85\xa1\x2c\xf7\x8e\xfe\x16\x94\
+\x4e\x07\x6c\xdc\xdf\xc0\x3a\xe5\xba\x49\xe4\xf3\x43\xa3\xee\xf9\
+\xb0\x53\x7b\xeb\x7e\x78\xd3\x51\x1f\x44\xc2\xa9\xcf\xbb\x7e\xad\
+\x80\xa1\xcd\xd5\x3b\xd5\xcf\x4d\x03\xc9\x76\xc4\x3e\x03\x2b\xe9\
+\x66\xd1\x3f\xbc\x21\xde\x4e\xa8\x9e\x71\x04\xa0\x52\xd7\x5d\xf7\
+\xb9\xe7\x01\x8c\xba\xfd\x6d\x3d\x1b\xcf\xcc\xff\x9d\xa4\x54\x65\
+\xdd\xd1\x2f\x5f\xfe\xd9\x8d\x80\xb8\xb3\xec\x50\x14\xbb\xd2\x5c\
+\x80\xd4\xa8\xaf\x91\xc2\xc2\xd1\x07\x9e\x81\xb7\x1d\x77\x7e\xdd\
+\x5e\xfc\x55\x00\x0c\x6e\xac\xce\xc5\xdf\x4e\x00\x99\x69\xa5\x8d\
+\x7d\xaa\x31\xfd\x3a\xe1\x64\xe2\xef\x84\xea\x98\x54\x2c\x00\x2a\
+\x26\x34\x80\xc7\x4d\xa7\x88\x43\xa1\x30\x0c\xa5\x46\x5f\xf7\xbf\
+\x93\x65\x59\x85\xf1\xaf\x00\x78\x85\xd6\xea\xa6\xb2\x83\x51\x55\
+\x24\x12\x29\x08\x21\xf6\xfa\xbd\x96\x54\x3b\xde\x76\xc2\xf9\x38\
+\x62\x46\x7d\x1d\xe1\xbb\xab\xd0\x03\x86\x5e\x2a\x15\x01\x71\xb2\
+\xdd\xd2\x1e\xfe\x2d\x53\x80\x98\x37\x5b\xdc\x8d\xe4\x22\x2f\x1a\
+\x85\x94\xc2\xe7\xdf\x90\x68\x3c\x66\x3a\x40\xd4\xb4\x56\x65\xdd\
+\xfd\x0b\x21\x9f\x9f\x58\x4f\x36\xe7\x01\xd4\x28\x21\x04\x12\x89\
+\xd4\xab\xbe\xf6\x9a\xfd\x4e\x46\xd7\x89\x9f\x47\x36\x3d\xcd\x50\
+\xb2\xca\x79\x43\x3b\x2e\xfe\xe3\xab\x6f\x27\xc4\x49\x96\x26\xf8\
+\xb5\x4c\x2d\xfd\xbc\xda\xd4\x08\x07\x76\x11\x95\x88\x02\x0b\x80\
+\x08\x68\x8d\x86\x9b\x08\x98\xcf\x0f\x8f\x78\xe2\xdf\xde\x48\x29\
+\xfe\x36\x91\x7e\x96\x2f\xbf\xe0\x61\x34\x60\x01\xd5\x28\x76\x7d\
+\x0c\x90\x70\xd3\x38\xf5\xb5\xe7\xe1\xf8\x83\xe7\x1b\x4c\x54\xb9\
+\xfc\x36\x20\xbf\xb5\x34\xc1\x35\x72\xa2\xf4\x8c\x3f\x33\xad\x74\
+\xd7\x6f\xf6\x80\xbe\x18\xab\x1b\xaa\x7b\x42\x60\x98\x93\x00\xa3\
+\xd1\x50\x17\x30\xa5\x14\x8a\xc5\x42\x59\xef\x11\xc2\x5e\x53\x41\
+\x97\x37\x01\xf8\xf7\x0a\xde\x4f\x31\x91\x52\x22\x91\x48\xa1\x23\
+\x73\x00\x4e\x39\xf2\xff\x41\xd6\xf1\x7c\x4d\x1d\xee\x98\xec\xe7\
+\x45\xdf\xb6\xb4\x01\xb7\xa5\x74\xf1\x17\x35\xf2\x5b\x54\xf0\x1a\
+\x76\x6a\x12\x45\x42\x0c\xb2\x00\x88\x80\x94\xf2\x51\x5d\xed\xcd\
+\xc2\x63\x34\x3c\x3c\x58\xd6\xdd\x3f\x20\x20\x84\xbe\x61\xa2\xfd\
+\x69\x2d\x6f\x12\x42\xb1\x00\xa8\x41\xd9\xd4\x3e\x78\xdd\x6b\xba\
+\x90\x49\xd4\xf7\xd6\xb2\x41\x11\x18\xde\x1c\xf1\xb6\xbe\xa2\x34\
+\xb4\xef\xb6\x00\xb6\x81\x21\xfe\xb1\xe4\x8b\xe3\xde\x97\x8b\x9a\
+\x92\xd8\xc6\x02\x20\x02\xbe\xef\x3f\x6a\xdb\x96\x06\xb0\xf7\x19\
+\x53\x75\x24\x08\x7c\x78\x5e\x79\xb7\x48\x42\x88\x60\xd5\xaa\xdc\
+\xda\x89\xf6\xb9\x75\x6b\xff\x9f\x3b\x3b\x33\x9b\x01\x70\xe1\x72\
+\x8d\x90\xc2\xc6\x41\x53\xde\x8c\x19\x93\x5e\x07\x51\xe7\x7f\xad\
+\x8b\x83\x40\x61\x3b\xa2\xd9\xd9\x4f\x00\x4e\x02\xb0\xd3\x80\x9b\
+\x42\xcd\xfe\x8b\xd7\xd0\x28\xf8\x55\xda\xd4\x80\xea\x92\x10\x62\
+\x0b\xe7\x00\x44\xe0\xc6\x1b\x2f\x1a\x40\x03\x1c\x0a\xa4\xb5\xc6\
+\xd0\xd0\x00\xca\xfd\xa4\xb4\x6d\x7b\x7d\x25\xfd\xae\x59\x93\x0b\
+\x00\x71\x7d\x25\x6d\x50\x74\xda\xd3\x33\xf0\xfa\x43\xfe\x15\xfb\
+\x4f\x3a\xa9\xae\x2f\xfe\x3b\xd7\xf7\x17\xb6\xa1\xa2\x8b\xbf\x90\
+\x80\x93\x2a\x2d\xdf\xcb\xee\x5b\x7a\xb6\xef\xa6\x51\xb3\x17\x7f\
+\x00\xc8\x17\xb7\x22\x88\xe3\x59\x07\x35\x0c\x21\xc4\x53\x1c\x01\
+\x88\x88\xd6\x78\x4c\x08\xec\x67\x3a\x47\x25\x8a\xc5\xfc\x98\xc7\
+\xfd\xee\x8d\x94\xf2\xae\x4a\xfb\x16\x42\x2f\xd3\x1a\x1f\xac\xb4\
+\x1d\x9a\x38\xdb\x4a\xe0\xe0\x29\xa7\x62\xdf\x8e\xe3\x6a\xf9\xda\
+\x36\x2e\x81\xb7\x63\xc8\x7f\x02\xf3\xe0\x84\x28\x2d\xd7\xb3\x93\
+\x80\x95\x2c\x2d\xe3\xab\x37\xdb\x06\xeb\xfe\x7e\x84\x62\x26\x04\
+\x1e\x66\x01\x10\x9d\x75\xa6\x03\x54\x42\xa9\xf2\x96\xfd\xed\x4a\
+\x08\xf9\xeb\x4a\xfb\xdf\xbc\x79\xf0\xb6\xce\xce\x96\x97\x00\x51\
+\xdf\x0f\x9b\xeb\xd4\xa4\xd6\xd7\xe0\xf0\x7d\x66\xc3\xb5\xeb\x7f\
+\xf3\x98\xe2\xc0\x8e\x2d\x7d\xc7\x79\xd7\x2f\xed\xd2\x05\xdf\x72\
+\x4b\xb3\xf6\x2d\xa7\x54\x04\xd4\xb3\xed\x43\x2c\x00\x68\x74\x42\
+\xc8\x07\xf8\x08\x20\x32\xfa\x39\xd3\x09\x2a\x91\xcf\x97\x3b\xf1\
+\xef\x65\xba\xb5\x55\xff\xa6\xd2\xfe\xd7\xac\xc9\x05\x42\x48\x3e\
+\x06\xa8\xb2\x94\xdb\x8e\xe3\x0e\x58\x80\x63\x67\xcc\xab\xff\x8b\
+\xbf\xde\x31\xe4\x3f\xc2\xf3\x7e\x69\x95\xee\xea\xdd\x4c\x69\x2b\
+\xde\x96\xc9\x40\x76\x3f\xa0\x75\x1f\x20\x3d\xa9\x74\x22\x9f\xed\
+\xd6\xff\xc5\x1f\x00\x36\xf7\x3f\x6d\x3a\x02\xd5\xb8\x4c\x46\x3d\
+\xc0\x11\x80\xc8\x88\xba\x2d\x00\x7c\xdf\x43\xb1\x38\xb1\xe7\x85\
+\xb6\x6d\x6f\x5e\xb6\x2c\x17\xc9\xc3\x46\xa5\xf4\x32\x21\xf0\xe1\
+\x28\xda\xa2\xd1\x49\x61\x63\xff\x49\xaf\xc7\x01\x93\x4f\x86\x14\
+\x8d\xf1\x31\xe0\x0d\x96\x2e\xf2\x89\x56\x40\x4a\x00\x56\xe9\xbf\
+\xc2\x06\x2c\x0b\x35\xfd\xcc\x3e\x4a\xa1\x0a\xb0\x65\xe0\x19\xd3\
+\x31\xa8\x86\x49\x29\xc3\x65\xcb\x72\x5c\x06\x18\x1d\xf1\x5c\x55\
+\x0f\x10\x8f\x48\x69\xe2\xdf\x20\x26\x9a\x5d\x08\xf9\xd7\xa8\xb2\
+\x6c\xdd\x3a\xf8\x3b\x3e\x06\x88\x97\x00\x30\x39\x7b\x04\x5e\x33\
+\xf5\x54\x24\x9d\xac\xe9\x38\x91\x72\x5b\x4d\x27\xa8\x0d\x9b\xfb\
+\xd7\x22\x54\x63\x1f\xdf\x4d\xcd\x4b\x08\x31\x0c\x00\x7c\x04\x10\
+\x11\xcb\x42\x15\x4f\x11\x8f\xce\xf0\xf0\xd0\xb8\xf7\xfb\xdf\x1b\
+\xcb\xb2\x26\xbc\xfe\x7f\x4f\x3b\x56\x03\x2c\x8f\xaa\x3d\xda\x5d\
+\x26\x39\x0d\xc7\x1f\xf4\x2e\x1c\x3d\xfd\xac\x86\xbb\xf8\xd3\x2b\
+\x36\x6c\x6d\xb8\x8d\x49\x29\x62\x52\x5a\xeb\x01\x80\x23\x00\x11\
+\xd1\x5a\x0d\xd6\xdb\x18\x63\x69\xe8\xbf\xbc\x1d\xff\x76\x27\x90\
+\x4c\xe2\xe7\x91\x05\xc2\xce\xd5\x00\xe2\xbc\x28\xdb\x6c\x76\xae\
+\xdd\x82\x83\xa6\xbc\x09\xfb\xb4\xbf\xb6\xae\x97\xf5\xd1\xd8\x34\
+\x34\x5e\xd8\xfc\x77\xd3\x31\xa8\xc6\x09\x61\x3d\x01\xb0\x00\x88\
+\x90\x3d\x58\x4f\x7b\x6f\x4f\x74\xcd\xff\xae\x2c\xcb\xda\x7e\xfd\
+\xf5\xb9\x6d\xd1\xa5\x02\xa4\x3c\xf0\x77\x61\xf8\xcc\x46\x00\x53\
+\xa3\x6c\xb7\x19\x09\x61\x61\x7a\xc7\xf1\x38\x70\xf2\x9b\x61\x5b\
+\x75\xb8\x96\x8d\xca\xb6\x6d\xf0\x39\x0c\x17\xb7\x9a\x8e\x41\xb5\
+\xef\x7e\x80\x8f\x00\x22\xa3\xf5\x04\x16\xd0\x1b\x34\x3c\x3c\x08\
+\xa5\x2a\xdb\x17\x55\x4a\x6b\x42\x07\x00\x8d\x66\xd9\xb2\x77\x86\
+\x42\xe0\xba\xa8\xdb\x6d\x36\x93\x5b\x0f\xc3\xc9\x87\xbc\x1f\x87\
+\x4c\x7b\x1b\x2f\xfe\x4d\xe4\xf9\x4d\xbc\xfb\xa7\xb1\xd9\x36\xfe\
+\x00\x70\x04\x20\x32\x42\xc8\x29\xf5\x72\x1e\x40\x69\xe8\xbf\x58\
+\x71\x3b\x8e\x23\xff\x27\x82\x38\xaf\x22\x84\xfe\x95\xd6\xe2\xa3\
+\x71\xb4\xdd\xe8\x32\xc9\xa9\x38\x74\xda\x2c\xb4\xa5\xf7\x37\x1d\
+\x85\xaa\x4c\x6b\x85\x67\x5f\xba\xcf\x74\x0c\xaa\x71\x42\x08\x58\
+\x16\x0b\x80\x48\x29\xa5\xf7\xa9\x87\xf5\xc3\x5a\x2b\x0c\x0e\x56\
+\x36\xf4\x5f\x22\x74\x4b\x0b\x7e\x10\x45\xa6\x3d\x1d\x7b\xec\xd0\
+\x1f\x1e\x7c\x30\xb3\x16\xc0\x41\x71\xb4\xdf\x88\x92\x4e\x1b\x0e\
+\x9e\xfa\x66\x4c\xcd\x1e\x89\x7a\x9b\x8b\x42\xd1\xd8\xb0\xf5\x11\
+\x14\x3c\xee\xff\x4f\xa3\x93\x52\x16\x6e\xba\x29\xc7\x55\x00\x51\
+\x92\x52\x9d\x66\x3a\xc3\x58\xb4\x06\x06\x07\x07\x10\xc5\x48\x85\
+\xe3\xd8\xcf\x44\xb5\xfe\x7f\x4f\xb9\x5c\x4e\x01\xfa\xc7\x71\xb4\
+\xdd\x68\x12\x4e\x06\x87\xed\x73\x06\x4e\x3e\xf4\x03\x98\x9a\x3d\
+\x0a\xbc\xf8\x37\xaf\xa7\x37\xdc\x6d\x3a\x02\xd5\x01\x21\xac\xe7\
+\x77\xfe\x9c\x23\x00\x11\x98\x37\xef\x8a\x63\xb5\x16\x1f\x31\x9d\
+\x63\x2c\x85\xc2\x30\x7c\x3f\x9a\x6b\xb6\x10\x56\x5f\x24\x0d\x8d\
+\xd8\xbe\xfd\x13\xad\xc3\x45\xe0\x15\x6d\xaf\x1c\x2b\x85\xfd\x27\
+\xbf\x1e\xd3\x3b\x66\x36\xcc\x46\x3e\x34\x71\xf9\xe2\x76\x2e\xff\
+\xa3\x71\x91\x52\xbe\xfc\x9c\x88\x23\x00\x15\x5a\xb0\xe0\xca\x23\
+\x85\x10\xab\x01\xd4\xf4\x36\x24\xbe\xef\x4d\x78\xaf\xff\xbd\x11\
+\xc2\xba\x36\xb2\xc6\xf6\xe2\x37\xbf\xb9\xe0\x29\x40\xff\x21\xce\
+\x3e\xea\x91\x25\x5d\x1c\x38\xf9\x8d\x38\xf9\x90\x0f\x61\xff\xce\
+\xd7\xf3\xe2\x4f\x00\x80\x27\x5e\xf8\x53\x24\x23\x7b\xd4\xf8\x6c\
+\x5b\xfe\xdf\xcb\x3f\x37\x19\xa4\xde\xbd\xe3\x1d\x57\x9d\xae\xb5\
+\x5e\x06\xa0\xc3\x74\x96\xd1\x28\xa5\x2a\x5e\xf2\xb7\x2b\xcb\xb2\
+\x86\xfa\xfa\x16\xfd\x23\x92\xc6\x46\xd1\x91\x3a\xe8\xf6\xad\xf9\
+\x75\x35\xff\x68\xa5\x1a\x84\xb0\xb0\x4f\xdb\x31\x38\x68\xca\x9b\
+\xe0\xda\x2d\xa6\xe3\x50\x0d\x09\xc2\x22\xd6\x71\xf8\x9f\xc6\x45\
+\x20\x91\xd0\x2f\x6f\xb6\xc6\x02\x60\x02\x16\x2e\xfc\x5f\x2b\x0c\
+\x9f\xb9\x48\x29\x9d\x03\xe0\x98\xce\x33\x96\xa1\xa1\xfe\x8a\x97\
+\xfc\xed\x4a\x4a\xfb\x9e\xc8\x1a\x1b\xc1\xd7\x2f\xd2\x07\x28\xe9\
+\x9f\x77\xfb\xe3\xff\xd5\xd4\xdb\x9a\x0a\x48\xec\xd3\x7e\x2c\x0e\
+\x9c\xfc\x06\x24\x9c\x9a\x1e\x64\x22\x43\xd6\x6e\xb8\x0b\x7e\x58\
+\xc9\x86\x5e\xd4\x2c\xa4\x94\xc5\xe5\xcb\x73\x1b\x77\xfe\x9a\x05\
+\x40\x99\xce\x39\xe7\xaa\xfd\xc3\x70\xdd\x4f\x01\x51\x17\x77\xa6\
+\xf9\xfc\x20\x7c\x3f\xda\x0b\xa8\x6d\xdb\x3f\x89\xb4\xc1\x3d\xfc\
+\x30\xa7\x93\xdb\x7d\xfc\x46\xc2\x99\x34\xa5\xf5\x70\xac\xdf\x1e\
+\xfb\x60\x43\xcd\x91\xc2\xc2\xb4\xb6\x63\x70\xc0\xe4\x93\x91\x74\
+\xda\x4c\xc7\xa1\x1a\xa5\x74\x80\x27\x5e\xf8\x93\xe9\x18\x54\x27\
+\xa4\xb4\x76\x3b\xb4\x8e\x05\x40\x19\xe6\xcd\xbb\x72\xbe\x10\xfa\
+\xfb\x80\xe8\x34\x9d\x65\x3c\x3c\xaf\x88\x7c\x3e\xda\x3b\x03\x29\
+\x65\x98\xcf\xab\x58\x0b\x80\x7e\x1f\x5f\x13\xc0\x49\x00\xb0\x4f\
+\xfb\x31\x4d\x55\x00\xec\xbc\xf0\xf3\x8e\x9f\xc6\x63\xed\xfa\xbb\
+\x91\x2f\x6e\x37\x1d\x83\xea\x84\x6d\x8b\xdd\xaa\x45\x16\x00\xe3\
+\xd0\xdb\x7b\x6d\x36\x99\xf4\xbe\x26\x04\x3e\x60\x3a\xcb\x78\x05\
+\x81\x1f\xd1\x7a\xff\xdd\xd9\xb6\x73\xff\xea\xd5\xb9\x20\xd2\x46\
+\x77\x71\xed\x25\xfa\x0c\xad\xf1\xf2\x8a\x8a\x6c\x7a\x7f\x24\x9d\
+\x36\x14\xfc\xc6\xfe\x90\xb3\xa4\x8b\xe9\x1d\x33\x31\xbd\xf3\x44\
+\xb8\x76\xda\x74\x1c\xaa\x03\xa1\x0a\xf0\xd8\xf3\x6b\x4c\xc7\xa0\
+\x3a\xa2\x14\x76\xdb\xbc\x8d\x05\xc0\x18\xe6\xcf\xbf\xea\x6c\xc0\
+\xfb\x16\x80\x19\xa6\xb3\x8c\x57\x18\x86\x18\x18\xe8\x47\x1c\xc7\
+\x13\x5b\x96\xfd\xed\xc8\x1b\xdd\xe1\xbb\x17\xe9\xb6\xa2\xc6\x0f\
+\xb0\xcb\xd2\x3f\x81\xd2\x28\xc0\xda\x97\x6e\x8f\xab\x5b\xa3\x1c\
+\x2b\x85\xe9\x9d\x33\xb1\x5f\xc7\x4c\x38\x56\xd2\x74\x1c\xaa\x23\
+\x4f\xbf\x78\x27\xef\xfe\x69\xdc\xa4\x94\x6a\xf5\xea\xa5\xb7\xee\
+\xfa\x35\x16\x00\x23\x38\xfb\xec\x6b\xa6\xd9\x76\x70\x05\xa0\xdf\
+\x6b\x3a\x4b\x39\x94\x52\x18\x18\xd8\x1e\xcb\x92\x20\x29\xad\x60\
+\xe5\x4a\xf5\xa3\xc8\x1b\xde\x21\x6f\xe3\x1a\x01\xbc\x6a\x0f\xdb\
+\x7d\xdb\x8f\xc3\xba\x4d\x7f\x81\xd6\x75\x75\xdc\xc2\xa8\x5c\x3b\
+\x8d\x7d\xdb\x8f\xc7\x8c\x49\xaf\x83\x2d\x13\xa6\xe3\x50\x9d\x09\
+\xc2\x22\xef\xfe\xa9\x2c\x52\xbe\xb2\x01\xd0\x4e\x2c\x00\x5e\x45\
+\x8b\x05\x0b\xae\x7e\x3f\x10\x5c\xa9\x75\x6d\x2f\xef\xdb\x93\xd6\
+\x1a\x03\x03\xdb\xa1\x54\x3c\x17\x4a\xdb\xb6\xef\x01\x72\xb1\x2c\
+\x36\xfe\xfa\x17\xf4\xe9\x00\xde\xb7\xb7\xef\xb9\x76\x0b\xa6\xb4\
+\x1e\x86\x8d\xfd\x8f\xc4\xd1\x75\x55\x25\x9d\x36\xcc\xe8\x3c\x09\
+\xfb\x76\x1c\xcb\x35\xfc\x34\x61\x8f\x3d\xb7\x06\x45\x7f\xd0\x74\
+\x0c\xaa\x23\x96\x25\xef\xdc\xf3\x6b\xfc\x04\xda\xc5\xc2\x85\x57\
+\x1f\x1a\x86\x57\x7d\x57\x6b\xbc\xdd\x74\x96\x72\x95\xb6\xf9\xdd\
+\x8e\x30\x8c\xed\xf1\x3c\x6c\x5b\x7e\x23\x8e\x76\x73\x39\x2d\x85\
+\x8f\xff\x1c\xed\x81\xc5\xf4\xce\x99\x75\x5d\x00\xb4\xa5\xa6\x63\
+\x7a\xe7\x89\x98\x9c\x3d\x0c\x82\x9b\x1b\x52\x05\xf2\xc5\xed\x9c\
+\xf9\x4f\x65\x13\xc2\xf9\xe5\x9e\x5f\x63\x01\x00\xe0\xbc\xf3\xbe\
+\xeb\xbc\xf4\x52\xff\x67\xc2\x50\xe5\x00\xd4\xe5\x83\xd8\xa1\xa1\
+\xed\x91\x2f\xf7\xdb\x95\x94\x96\xb7\x62\x45\xee\xe7\x71\xb4\xdd\
+\x11\xe0\x5f\x35\x70\xe2\x68\xaf\xc9\xa6\xf6\x43\x6b\x6a\x1f\x0c\
+\xe4\xd7\xc7\x11\x21\x26\x02\x93\x5a\x0f\xc6\x01\x93\x4e\x41\x36\
+\xb5\x9f\xe9\x30\xd4\x20\xfe\xb6\xf6\x96\xa6\xde\x1b\x83\xca\x27\
+\xa5\x0c\x57\xad\x0a\xaf\xdf\xf3\xeb\x4d\x5f\x00\x2c\x58\x70\x65\
+\xf7\xa6\x4d\x03\xdf\x14\x42\x1c\x6a\x3a\xcb\xc4\x68\x0c\x0c\xf4\
+\x47\xb6\xc7\xff\x48\x1c\xc7\xfe\x4b\x1c\xed\x7e\x37\xa7\xd3\x05\
+\x0f\x4b\xc7\x73\x53\x3c\xbd\x63\x26\x1e\xc9\xaf\x8c\x23\x46\xa4\
+\x6c\x2b\x81\x7d\xdb\x8e\xc3\xf4\xce\x99\x5c\xca\x47\x91\xda\xdc\
+\xbf\x16\x2f\x6c\xfa\x9b\xe9\x18\x54\x67\x2c\xcb\x7e\x7c\x6f\x8f\
+\x6f\x9b\xb6\x00\x38\xfb\xec\xaf\xee\x67\xdb\xd6\x57\xb4\x46\x5d\
+\x4d\xf2\xdb\x9d\xc6\xc0\xc0\x40\xec\x17\x7f\x40\x40\x4a\x99\x8b\
+\xa3\xe5\x82\x87\x0b\x20\xc6\xb7\xc2\x62\x6a\xf6\x08\x3c\xb5\xf1\
+\x0f\xf0\x82\xa1\x38\xa2\x54\x2c\xe9\xb4\x61\xdf\x8e\xe3\xb0\x5f\
+\xfb\xf1\xb0\x2d\x4e\xec\xa3\x68\x29\x1d\xe2\xfe\x27\x97\x43\xc7\
+\xb0\xba\x87\x1a\x9b\x65\xc9\x57\xdd\xfd\x03\x4d\x58\x00\x94\x86\
+\xfb\x07\x3f\x25\x84\x5e\x0c\x20\x63\x3a\xcf\x44\x69\xad\x31\x38\
+\x18\xef\xb0\xff\x4e\xb6\x6d\x6f\x59\xb9\x32\xf7\xdb\xa8\xdb\xbd\
+\xe2\x42\xdd\x02\x81\x0b\xc6\xfb\x7a\x21\xac\x1d\x2b\x02\xee\x88\
+\x3a\x4a\x45\xda\xd3\x33\x30\xbd\xf3\x75\x98\xdc\x7a\x08\x78\x78\
+\x21\xc5\xe5\x89\xe7\xff\x88\xfe\xe1\x0d\xa6\x63\x50\x1d\xd2\xda\
+\xdd\xeb\xe1\x6d\x4d\x55\x00\xcc\x9f\x7f\xe5\xa9\x9b\x36\x0d\x7c\
+\x4b\x08\x1c\x6b\x3a\x4b\x25\xb4\x2e\x2d\xf5\x0b\x82\xf8\x26\xfc\
+\xed\xca\xb6\xed\x1f\xc7\xd1\x6e\x22\x81\x0f\x6b\x60\x52\x39\xef\
+\xd9\xb7\xfd\x38\x3c\xb3\xe9\x2f\xd0\x30\x7b\xf2\x99\x6d\x25\x30\
+\xad\xed\x68\xec\xd7\x71\x3c\xd2\x6e\x59\xff\x0b\x44\x65\xcb\x7b\
+\xdb\xf0\xc8\xb3\x91\xd7\xe0\xd4\x04\x6c\xdb\xde\xd2\xd7\x77\xf1\
+\x8b\x7b\xfd\x5e\xb5\xc3\x98\x30\x7f\xfe\xd7\xf6\x05\xc2\xaf\x02\
+\x78\x0f\xea\xfc\x16\x2d\x0c\xc3\x1d\xb3\xfd\xab\xb3\x26\x5e\x4a\
+\xa9\x5c\x37\xb5\x38\xea\x76\x73\x39\x2d\xb5\x8f\xf3\xcb\x7d\x5f\
+\xc2\xc9\x60\x4a\xf6\x08\x6c\xec\x7f\x38\xea\x48\xe3\xd2\x9a\x9a\
+\x86\x7d\xdb\x8f\xc3\xb4\xb6\xa3\x20\x45\xcd\x9f\x03\x45\x0d\xe2\
+\xfe\x27\xae\x47\xa8\xe2\x7e\xd4\x47\x8d\xc8\xb2\xec\x11\x97\x8c\
+\x34\x74\x01\xb0\x70\x61\xce\x0d\xc3\xcc\xa7\x81\xf0\x52\xd4\xf1\
+\x70\xff\x4e\x41\xe0\x63\x60\xa0\xbf\xaa\xe7\x7e\x5b\x96\x73\xcf\
+\x8d\x37\x5e\x34\x10\x75\xbb\x9d\x01\xce\xd0\xc0\xc1\x13\x79\xef\
+\x8c\xce\x99\x55\x2d\x00\x2c\xe9\x60\x6a\xf6\x28\xec\xd7\x71\x1c\
+\x32\xc9\x69\x55\xeb\x97\x08\x00\xd6\x6d\xbc\x17\xeb\xb7\xd6\xef\
+\x12\x58\x32\xcb\xb2\xc4\x7f\x8d\xf4\xbd\x86\x2d\x00\xe6\xcd\xbb\
+\xe2\xed\x61\x28\xae\x05\x70\x8c\xe9\x2c\x51\xf0\xbc\x22\x86\x86\
+\xfa\xa1\xab\x3a\xff\x47\xc0\xb6\x9d\x4b\x63\x69\x5a\x4f\xfc\x5c\
+\x85\xd6\xd4\xbe\xe8\x68\x39\x00\x5b\x87\x9e\x89\x32\xd1\xab\xa4\
+\xdd\x4e\x4c\x6b\x3f\x06\xfb\xb5\x1f\x07\x9b\xdb\xf4\x92\x01\x05\
+\xaf\x1f\x7f\x7f\xfa\x66\xd3\x31\xa8\x4e\x49\x69\x05\x2b\x56\xe4\
+\x56\x8d\xf4\xfd\x86\x2b\x00\xce\x3d\xf7\x6b\x07\x49\xa9\xae\x06\
+\xf4\x3c\xd3\x59\xa2\xa0\x35\x30\x3c\x3c\x88\x62\x31\x5f\xf5\xbe\
+\x2d\xcb\xda\xb6\x72\xe5\xa5\xab\xa3\x6e\xf7\xab\x9f\xd3\xad\x1a\
+\x38\xa7\x92\x36\x0e\x98\xfc\x86\x58\x0a\x00\xdb\x4a\x60\x4a\xf6\
+\x08\xec\xd3\x76\x0c\xd7\xee\x93\x71\xf7\x3d\x71\x1d\xbc\xa0\xfa\
+\xff\xf6\xa9\x31\xd8\xb6\xfd\xe0\xa8\xdf\xaf\x56\x90\xb8\x2d\x5c\
+\x98\x73\x95\xca\x7c\x4c\xeb\xf0\x32\x34\xc0\x70\x3f\x00\x28\x15\
+\x62\x70\xb0\xbf\x6a\x93\xfd\xf6\x64\xdb\xce\xb7\xe2\x68\x37\xe1\
+\xa0\x07\x15\x6e\xb8\xd4\x9e\xde\x1f\x6d\xa9\xe9\xd8\x9e\x7f\xd5\
+\xf6\xd6\x65\x13\x10\x68\x6f\x39\x00\xd3\xda\x8e\xc6\x94\xec\x61\
+\x7c\xb6\x4f\x35\x61\xdd\x86\x7b\x38\xf4\x4f\x15\xb2\xf6\x3a\xfb\
+\x7f\xa7\x86\x28\x00\x16\x2c\xb8\x62\x6e\x18\x8a\x6b\x00\xbc\xc6\
+\x74\x96\xa8\x14\x8b\x05\x0c\x0d\x0d\x22\x8e\x13\xfd\xc6\xc3\xb2\
+\x2c\xaf\x58\x44\x2e\xa6\xe6\x23\x19\x9d\xd9\x7f\xf2\xc9\xd8\xfe\
+\xec\xf2\x09\xbf\x3f\xed\x4e\xc2\xb4\xf6\xa3\xb1\x4f\xdb\xb1\x3c\
+\x82\x97\x6a\xca\x50\x61\x33\x1e\x7c\xfa\x26\xd3\x31\xa8\x8e\x09\
+\x21\xfd\xd5\xab\xf5\x4f\x47\x7b\x4d\x5d\x17\x00\xa5\xbd\xfb\xd5\
+\x35\x5a\xe3\x4c\xd3\x59\xa2\xa2\x94\xc2\xf0\xf0\x00\x3c\xcf\xec\
+\x8c\x5f\xcb\x72\x7e\x76\xdb\x6d\xb9\xc8\x87\x1e\x34\xb4\xb8\x16\
+\x98\x1d\x45\x5b\x93\x32\xaf\x41\x36\xb5\x2f\xfa\xf3\x7b\x5d\xe1\
+\xb2\x57\xae\x9d\xc1\xd4\xec\xe1\x98\xd6\x76\x0c\x32\xc9\xa9\x51\
+\xc4\x20\x8a\x94\xd2\x21\xee\x7e\xec\x17\x08\xc2\xa2\xe9\x28\x54\
+\xc7\x6c\xdb\xb9\x6b\xac\xc3\xdb\xea\xb2\x00\x78\xef\x7b\xaf\x68\
+\x19\x1c\x14\x97\x84\xa1\xfa\x0c\x00\xd7\x74\x9e\x68\x68\x14\x8b\
+\x45\x0c\x0f\x0f\x42\x57\x77\xa6\xdf\xab\x48\x29\xc2\xb6\x36\xf1\
+\xa9\x38\xda\xbe\xe6\x12\x1c\x29\x35\x26\x47\xd5\xde\xc1\x53\xdf\
+\x82\x07\xd6\x2d\x1b\xf5\x35\x09\x3b\x8b\xc9\xd9\x43\x31\xa5\xf5\
+\x30\xb4\xa5\xa7\xa3\xce\x57\x82\x52\x83\x7b\x78\x5d\x1f\xb6\x0e\
+\x3c\x67\x3a\x06\xd5\x39\xcb\x72\xae\x1e\xeb\x35\x75\x57\x00\x2c\
+\x58\x70\xc5\xdc\xa1\x21\xf1\x0d\x21\x70\xa0\xe9\x2c\x51\x09\xc3\
+\x00\x43\x43\x03\xc6\x9e\xf5\xef\xc9\xb6\x13\x2b\x97\x2d\xcb\xc5\
+\x72\xd6\xa8\x00\xde\x12\x65\x7b\xed\xe9\x03\xd0\x9e\x3e\x00\xdb\
+\x86\x77\x9f\x10\x98\x74\xda\x30\xb9\xf5\x10\x4c\x6e\x3d\x1c\xd9\
+\xf4\x74\x5e\xf2\xa9\x2e\x6c\xda\xfe\x14\x1e\x7b\xfe\x8f\xa6\x63\
+\x50\x9d\xb3\x2c\xcb\x5b\xb5\xea\xd2\xeb\xc6\x7a\x5d\xdd\x14\x00\
+\x0b\x16\x5c\x7d\x8c\x52\xea\x9b\x5a\x63\x96\xe9\x2c\x51\x51\x4a\
+\x21\x9f\x1f\x42\xb1\x58\x30\x1d\xe5\x65\x42\x08\xed\xba\x6d\x1f\
+\x8d\xad\x7d\x85\x99\x51\x5f\x8d\x0f\x9e\xfa\x56\xdc\xbf\xf6\x7f\
+\x90\x49\x4e\xc3\xe4\xec\x61\x98\xdc\x7a\x18\xd2\x6e\x67\xb4\x9d\
+\x10\xc5\xac\xe0\xf5\xe3\xae\x47\x7f\x0e\x53\xf3\x7e\xa8\x71\x58\
+\x96\x33\xae\xf3\xa2\x6b\xbe\x00\x58\xb8\xf0\x5b\x19\xa5\x86\x17\
+\x6b\xad\x3e\x25\x04\x1a\x62\x7a\xb6\xd6\x0a\xf9\xfc\x30\x0a\x85\
+\x02\x6a\xed\x1f\xbb\x6d\xbb\xb7\xdf\x7c\xf3\x67\x2a\x9f\x5a\x3f\
+\x12\x81\xc3\xa2\x6e\x32\x9b\xda\x07\x6f\x38\xec\x63\x9c\xc8\x47\
+\x75\x4b\xe9\x10\x77\x3f\xfa\x0b\x14\xfd\x58\x06\xde\xa8\xc9\x58\
+\x96\xfd\xd5\xf1\xbc\xae\xa6\x0b\x80\xd2\xec\xfe\xc2\x37\x01\x71\
+\x80\xe9\x2c\x51\x50\x2a\x44\xa1\x90\x47\xb1\x98\xaf\xf2\x86\x3e\
+\xe3\x23\x84\xd0\x8e\x13\xfe\x4b\xbc\x9d\xe0\xf0\x38\x6a\x1e\x5e\
+\xfc\xa9\x9e\xfd\xfd\xe9\x15\xd8\xd4\xff\xb4\xe9\x18\xd4\x00\xa4\
+\xb4\x07\xc6\xbb\x7f\x4b\x4d\x16\x00\xa5\xd9\xfd\xe1\x37\xb4\x16\
+\x3d\xb5\x76\x87\x3c\x11\x41\xe0\xa3\x50\xc8\xc3\xf3\x6a\x7b\x56\
+\xaf\xe3\x24\x6f\x5e\xb1\x22\xb7\x2e\xae\xf6\x73\x39\x2d\xe1\x8f\
+\xef\xe8\x5f\xa2\x66\xf1\xfc\xa6\x07\xf1\xe4\x8b\x7f\x36\x1d\x83\
+\x1a\x84\x6d\x5b\x3f\x1f\xf7\x6b\xe3\x0c\x52\xae\x85\x0b\xaf\x4e\
+\x85\x61\x78\x51\x18\xaa\xcf\x03\xa2\xae\x0f\x54\xd7\x5a\xc3\xf3\
+\x8a\x28\x16\xf3\x35\x33\xb9\x6f\x34\x52\x8a\x50\x08\xbc\x2f\xce\
+\x3e\x3a\x81\x8c\x06\x64\x9c\x7d\x10\xd5\x93\xfe\xe1\x0d\xf8\xeb\
+\x13\xbf\x36\x1d\x83\x1a\x84\x10\x42\xa7\xd3\xf2\xf3\xe3\x7d\x7d\
+\xcd\x14\x00\x0b\x16\x5c\x35\x27\x0c\xd5\xb7\x01\x51\xb7\xb3\xfb\
+\xb5\x2e\xdd\xed\x7b\x5e\xa1\xa6\x26\xf6\x8d\x87\x6d\x27\x7f\xd4\
+\xd7\x97\xdb\x12\x73\x37\xd9\x98\xdb\x27\xaa\x1b\x5e\x30\x8c\x3b\
+\x1f\xfe\x09\x82\x90\xa7\xfc\x51\x34\x6c\xdb\xbd\xe7\xfa\xeb\x73\
+\xdb\xc6\xfd\xfa\x38\xc3\x8c\xc7\xd9\x67\x5f\x33\xcd\xb6\x83\x2b\
+\xb4\xd6\xef\x35\x9d\x65\x62\x34\x7c\x3f\x80\xef\x17\xe1\x79\x45\
+\x28\x65\xf6\x9c\xfa\x89\x90\x52\x16\x2d\x6b\xf3\x27\x62\xef\xa7\
+\x88\x74\xc8\xfb\x7f\x22\x68\x1d\xe2\xce\x87\x7f\x8a\xa1\xc2\x66\
+\xd3\x51\xa8\x61\x08\x08\x61\x5d\x5c\xce\x3b\x0c\x16\x00\x5a\x2c\
+\x58\x70\xf5\xfb\xb5\x0e\xae\x00\x50\x57\x6b\xb6\x94\x52\xf0\x7d\
+\x0f\x9e\x57\x44\x10\xf8\xc6\x37\xee\xa9\x94\xeb\xa6\x2e\x5b\xb9\
+\xf2\xcb\xb1\x4f\x50\x08\x15\x0a\x7c\x00\x40\x04\xdc\xff\xe4\x0d\
+\xd8\xcc\x49\x7f\x14\x21\xcb\xb2\x36\xaf\x5e\xbd\xf8\xd6\x72\xde\
+\x63\xa4\x00\x38\xf7\xdc\xff\x3c\x44\xca\xab\xbe\xa3\x35\xce\x30\
+\xd1\x7f\x39\xb4\xd6\x50\x2a\x84\xef\xfb\x08\xc3\x00\x41\xe0\x23\
+\x0c\x15\x1a\x61\x72\x22\x00\x38\x8e\xfb\xcc\xaa\x55\x8b\x2e\xab\
+\x46\x5f\x96\xc4\x50\x58\x8d\x8e\x88\x6a\xd8\x13\xcf\xff\x09\x6b\
+\x37\xdc\x65\x3a\x06\x35\x18\xdb\x76\xfe\xbb\xec\xf7\xc4\x11\x64\
+\x24\xb9\x5c\x4e\x3e\xf0\x40\xcb\x67\x85\x10\x39\x54\x78\x1a\x5c\
+\xb4\x34\x94\xd2\x50\x4a\x21\x0c\x03\x28\x15\x22\x08\x42\x28\x15\
+\x22\x0c\x6b\x7f\x02\xdf\x44\x09\x21\x34\x90\xac\xe8\x58\xde\x72\
+\xa8\x41\x0c\x72\x16\x00\x35\xb3\x17\x36\xff\x03\x7f\x5f\xbb\xc2\
+\x74\x0c\x6a\x30\x52\x5a\xc1\x44\x0e\x6f\xab\xda\x0e\xa9\x0b\x17\
+\x7e\xa5\x4d\x29\xfb\x17\x5a\xa3\xb7\x5a\x7d\xee\x54\xba\x8b\x57\
+\x08\xc3\x10\x5a\x87\x08\x43\x05\xad\x15\xc2\x50\x41\xa9\xd2\x85\
+\xbe\x19\xb9\x6e\xf2\x97\xab\x57\x2f\xf9\xe7\x6a\xf6\x79\xcd\xc5\
+\x7a\x83\x00\x78\x0a\x0f\x35\x9d\xad\x83\xcf\xe2\x8f\x7f\xfb\x1e\
+\x42\xe5\x9b\x8e\x42\x0d\x26\x91\x48\xfc\xaa\xaf\x6f\xe9\x3f\x95\
+\xfb\xbe\xaa\x8c\x00\x94\x96\xf7\xa9\x1b\x01\x9c\x5a\x8d\xfe\xb4\
+\x56\xf0\x7d\x1f\xbe\xef\x21\x08\x7c\x28\xa5\xea\xfe\x39\x7d\xd4\
+\x2c\xcb\x1e\xf4\x3c\x51\xf5\x89\x97\x02\x78\x0c\x2c\x00\xa8\xc9\
+\x0c\x15\x36\xe3\x8e\x87\x7e\xcc\x8b\x3f\x45\x4e\x4a\xa9\x00\xf9\
+\xf1\x89\xbc\xb7\x2a\x05\x40\x18\x86\x5f\x03\x44\xec\x17\xff\x5a\
+\xdc\x5b\xbf\x16\x09\x21\xe0\xba\xc9\xf7\xae\x5c\x79\xa9\x89\xe7\
+\x1b\x8f\x21\xe2\x03\x81\x88\x6a\x59\xd1\x1f\xc2\xed\x0f\xfd\x90\
+\xdb\xfc\x52\x2c\x6c\x3b\x71\xcb\x44\x97\x70\xc7\x5e\x00\xcc\x9b\
+\x77\xf5\x69\x80\x3a\x2f\xee\x7e\xc2\x30\x40\x7f\xff\x76\x68\x5d\
+\x7f\xcb\xf0\xaa\xcd\x71\x12\xbf\x5c\xb9\xf2\xd2\xeb\x4d\xf4\xad\
+\x81\xfb\x78\x32\x1f\x35\x8b\x20\x2c\xe2\xf6\x87\x7e\x80\xc1\xfc\
+\x26\xd3\x51\xa8\x01\x09\x21\x74\x32\xd9\xfe\xe1\x89\xbe\x3f\xf6\
+\x45\x59\x42\xa8\xc5\x88\x79\xae\x81\xd6\x0a\x03\x03\xbc\xf8\x8f\
+\x87\x6d\xbb\x2f\x54\xfb\xb9\xff\xae\xa4\xc2\x6f\x4d\xf5\x4d\x54\
+\x4d\xa1\xf2\x71\xc7\x43\x3f\xc6\xb6\xc1\xf8\xce\xd6\xa2\xe6\xe6\
+\xba\xee\x6f\x6f\xbc\xf1\xd3\x1b\x26\xfa\xfe\x58\x0b\x80\x79\xf3\
+\xae\x38\x16\xc0\xdb\xe2\xec\x03\x00\xf2\xf9\xe1\xba\xdc\x80\xa7\
+\xda\xa4\x94\xa1\xe3\xe8\xaa\xcc\xc3\x18\xc9\xf9\x5f\x16\x0f\x01\
+\xe0\x27\x22\x35\x34\xa5\x43\xdc\xf5\xc8\xff\x60\x53\xff\x53\xa6\
+\xa3\x50\xe3\xd2\x5a\xab\x09\xdf\xfd\x03\x31\x17\x00\x42\xe0\x9d\
+\x71\xb6\x5f\xa2\xf9\xcc\x7f\x1c\x84\x10\x48\x26\x53\xff\xb6\x72\
+\xe5\x65\x4f\x9a\xcf\x82\xdb\x4c\x67\x20\x8a\x8b\x86\xc2\x3d\x8f\
+\xfd\x12\xeb\xb7\x3e\x62\x3a\x0a\x35\xb0\x44\x22\xf1\xdb\xd5\xab\
+\x2f\xab\x68\x37\xa9\x98\x1f\x01\x88\xae\x78\xdb\x07\x82\x20\xe0\
+\x0c\xff\x31\x09\xb8\x6e\xe2\xbf\x57\xac\x58\xf4\x1d\xd3\x49\x00\
+\x40\x29\xfc\xcc\x74\x06\xa2\x38\x68\x68\xdc\xf7\xf8\x75\x78\x7e\
+\xd3\xdf\x4c\x47\xa1\x06\x26\xa5\x0c\x83\xc0\x7f\x57\xc5\xed\x44\
+\x11\x66\x6f\x7a\x7b\xaf\x4d\x00\x38\x21\xae\xf6\x77\x0a\x02\x2e\
+\xab\x19\x4b\x22\xe1\xfe\xae\xaf\x6f\x49\x45\x43\x45\x51\xfa\xd4\
+\xe5\xf8\x3f\x00\x1c\x1b\xa5\x86\xa2\xa1\xf1\xe0\x53\x37\x62\xdd\
+\xc6\x7b\x4c\x47\xa1\x06\x67\xdb\xce\xb7\x6f\xbb\xed\xcb\x15\x1f\
+\x24\x11\x5b\x01\x90\xc9\x78\x87\x00\x88\xfd\x48\x5f\x3e\xfb\x1f\
+\x9d\x6d\xbb\x8f\xf5\xf5\x2d\x7d\xbb\xe9\x1c\xbb\x12\x10\x1a\x1a\
+\x3f\x31\x9d\x83\x28\x2a\x3b\x2f\xfe\x4f\xbd\x78\x87\xe9\x28\xd4\
+\xe0\x2c\xcb\x1a\x58\xbd\x5a\x7e\x3a\x8a\xb6\x62\x2b\x00\xc2\x50\
+\x1f\x1c\x57\xdb\xbb\xe2\xf0\xff\xc8\x6c\xdb\x7d\x21\x08\xac\xe3\
+\x4d\xe7\xd8\x1b\x05\x7c\x0f\x40\xde\x74\x0e\xa2\x4a\x95\x2e\xfe\
+\x37\xf0\xe2\x4f\x55\x20\x60\xdb\x89\x4f\x01\xb9\x48\xee\x7c\x63\
+\x2b\x00\x84\x90\xd3\xe2\x6a\x9b\xc6\xe6\x38\xee\x53\x41\x60\x1d\
+\xb2\x66\x4d\xae\x26\x67\x48\x5e\x70\xb9\x78\x51\x03\xdf\x35\x9d\
+\x83\xa8\x12\xaf\xdc\xf9\xdf\x69\x3a\x0a\x35\x01\xdb\x76\x9e\xec\
+\xeb\x5b\xfc\xc3\xc8\xda\x8b\xaa\xa1\x57\xd3\xad\xf1\xb5\xfd\x0a\
+\x21\xb8\xad\xcc\x9e\x1c\x27\xf1\xc0\xad\xb7\xca\x13\xa3\xaa\x12\
+\xe3\x22\x15\x2e\xd7\x12\xef\x05\x30\xc9\x74\x16\xa2\x72\x69\xad\
+\xf1\xc0\x53\xd7\xe3\xe9\xf5\x7f\x31\x1d\x85\x9a\x80\x10\x42\x3b\
+\x8e\xb3\x30\xca\x36\x63\x1b\x01\xd0\xba\x5a\x27\x0d\xb2\x00\xd8\
+\x55\x22\x91\xfc\xdf\x5b\x6f\x5d\x7a\x42\xad\x5f\xfc\x01\xe0\xfc\
+\x2f\x8b\x97\xb4\xc0\x45\xa6\x73\x10\x95\x4b\x43\xe1\xbe\x27\x7e\
+\xcd\x8b\x3f\x55\x8d\xe3\x24\x7f\xb0\x72\xe5\xa2\xfb\xa2\x6c\x33\
+\xc6\x47\x00\xba\x18\x57\xdb\xbb\xf7\xc3\x02\x00\x00\x2c\xcb\x2a\
+\x24\x93\xe9\x77\xf6\xf5\x2d\xa9\x78\x69\x48\x35\x7d\xea\x32\xfc\
+\x00\xc0\x72\xd3\x39\x88\xc6\x4b\xeb\x10\x77\x3d\xf2\x73\xac\xdb\
+\x78\xaf\xe9\x28\xd4\x24\x6c\xdb\xd9\xb8\x7a\x75\xee\x43\x51\xb7\
+\x1b\xe3\x08\x80\xa8\xca\xb3\x67\x29\x59\x00\x38\x4e\xe2\x4f\x9d\
+\x9d\xee\x94\x55\xab\x16\x2f\x33\x9d\xa5\x5c\x02\x42\x3b\x21\x3e\
+\x08\xc0\xf8\x06\x45\x44\x63\x09\x95\x87\xdb\x1f\xfa\x21\x5e\xd8\
+\xfc\x77\xd3\x51\xa8\x49\x08\x21\xb4\x6d\x8b\xb3\xe2\x68\x3b\xb6\
+\x61\x7a\x21\x44\xa1\x1a\x33\xf4\xa5\xb4\x62\xef\xa3\x16\x49\x29\
+\x95\x6d\x3b\x77\x59\x96\xfd\xf1\xa8\x87\x85\xaa\xed\xe3\x5f\x11\
+\x5b\xbf\x7e\x89\xee\x85\xc6\x9f\x01\x4c\x31\x9d\x87\x68\x6f\xfc\
+\x20\x8f\xdb\x1f\xfa\x11\xb6\x0c\xac\x33\x1d\x85\x9a\x48\x22\x91\
+\xfc\xfe\xaa\x55\xb9\xbb\xe3\x68\x3b\xce\xe7\xf4\x55\x59\xe2\xd5\
+\x4c\x05\x80\x94\x56\x20\xa5\x7c\x44\x4a\xf9\xcb\x81\x81\x81\xab\
+\xef\xb8\xe3\xcb\x0d\xb3\x8c\xee\x53\x97\x89\xc7\xaf\xbd\x54\x77\
+\x6b\x85\x3e\xb0\x08\xa0\x1a\x93\x2f\x6e\xc7\xed\x0f\xfd\x00\xfd\
+\xc3\x13\x3e\x77\x85\xa8\x6c\xb6\xed\x6c\x5c\xb5\x2a\xf7\x91\xd8\
+\xda\x8f\xab\x61\xa5\xf4\x86\x6a\x3c\x9e\xb7\xac\xd8\x0f\x34\x34\
+\x4a\x4a\x59\xb4\x6d\xe7\x3e\x29\xe5\x4f\x57\xad\xc2\x77\xea\x61\
+\x72\xdf\x44\x9d\xff\x45\x71\xdf\xd7\x2e\xd1\xa7\x49\x60\x15\x34\
+\x0e\x30\x9d\x87\x08\x00\x06\x86\x37\xe0\xcf\x0f\xfd\x00\xf9\xe2\
+\x76\xd3\x51\xa8\x89\x48\x29\x43\xdb\xb6\x67\xc7\xd9\x47\x6c\x05\
+\x80\x6d\x07\xcf\x84\x61\x35\x16\x02\x08\x48\x29\x1b\x66\x47\xc0\
+\xd2\x5d\xbe\xf5\x94\x65\x59\xbf\x95\x52\x7e\xaf\xde\x87\xf7\xcb\
+\x75\xc1\x65\xe2\xe1\x2b\x73\xfa\x75\xb6\x8f\x5f\x09\xa0\xa6\x76\
+\x30\xa4\xe6\xb3\x65\xe0\x19\xdc\xf1\xd0\x8f\xe0\x05\xc3\xa6\xa3\
+\x50\x13\x11\x42\xc0\x71\x9c\x4f\xad\x5a\x95\x7b\x30\xd6\x7e\xe2\
+\x6a\x78\xd6\xac\x9c\xdd\xd9\x99\x29\x00\x88\x7d\x8c\x7e\x60\x60\
+\x1b\x7c\xbf\x3e\xcf\x04\x90\x52\x86\x96\x65\xaf\x13\x42\xae\x91\
+\xd2\xf9\xe1\xaa\x55\x97\xfc\xc9\x74\xa6\x5a\x90\xcb\x69\xbb\x23\
+\xc0\x27\xa0\xf1\x25\x00\x2d\xa6\xf3\x50\xf3\x79\x61\xf3\x3f\x70\
+\xcf\x63\xbf\x44\xa8\xea\xf3\xb3\x85\xea\x57\x22\x91\xf8\x55\x5f\
+\xdf\xd2\x7f\x8a\xbb\x9f\x58\x07\xe9\xe7\xcf\xbf\xf2\x19\x00\xfb\
+\xc7\xd9\x07\x00\x0c\x0d\x0d\xa2\x58\xac\x87\xc7\xe1\x02\xb6\x6d\
+\xf5\x0b\x61\x3d\x6d\x59\xf2\x2f\x52\x8a\x15\x2b\x56\x2c\xbe\xc1\
+\x74\xaa\x5a\x76\xf5\xe7\xf5\xa1\xb6\x85\xef\x6b\x60\x96\xe9\x2c\
+\xd4\x3c\x9e\x78\xfe\x4f\xf8\xdb\xda\x5b\x00\x70\xab\x71\xaa\x2e\
+\xc7\x71\xd7\xde\x7a\xeb\x17\xab\xb2\x95\x7e\xcc\x63\xf4\xe2\x19\
+\x40\xc7\x5e\x00\xd8\xb6\x8d\x62\x55\x76\x1d\x28\x8f\x65\xd9\x83\
+\x52\x5a\xcf\x00\xb8\xd7\xb2\xac\x9b\x5a\x5b\xf5\x0d\xcb\x96\xe5\
+\x3c\xd3\xb9\xea\xc9\x67\xbe\x82\x27\x17\x9c\x7b\xd5\xf7\x66\xee\
+\xf7\xe1\xb7\xa6\x5b\xb3\x96\x55\xa5\xed\xa5\xa8\x39\x29\x1d\xe2\
+\x81\x27\x6f\xc0\xda\x0d\x77\x99\x8e\x42\x4d\x48\x4a\x3b\x9f\xc9\
+\xa4\x4e\xaa\x56\x7f\x71\x7f\x9c\x3e\x02\xe0\xcd\x31\xf7\x01\xdb\
+\x36\x79\x55\x10\x90\x52\x06\x42\x88\xed\x52\x5a\x4f\x48\x29\xef\
+\x06\xc4\xaa\x6c\x56\xdf\xca\x8b\x7d\x65\x16\x2c\xb8\xe2\x38\xad\
+\xaf\xfa\x86\x06\x4e\x0d\x3c\x81\xc1\xf5\x80\x9b\x06\xdc\x56\xc0\
+\x72\x4c\xa7\xa3\x46\xe3\x05\x79\xdc\xf5\xc8\xcf\xf0\xd2\x76\x6e\
+\x49\x41\xd5\x27\xa5\x50\xc9\xa4\xd3\xb3\x7c\xf9\x17\x2a\x3e\xe6\
+\x77\xbc\x62\xbd\x72\x0a\x81\x87\xaa\x71\x58\x9f\x94\x16\x84\x00\
+\xe2\xec\xab\xb4\xe3\xa0\xf0\x2d\xcb\xda\x22\xa5\x7c\x5a\x4a\xf9\
+\x04\x80\x3b\xb4\x76\x96\xf7\xf5\x5d\xfc\x62\x7c\x3d\x37\x9f\x33\
+\xcf\xfc\x72\x47\x32\xe9\xe6\xb4\xd6\x1f\xc7\x8e\xbf\xa3\x21\x3c\
+\x48\x00\xde\x70\xe9\x87\xe5\x02\x6e\x0b\xe0\xa4\x00\xd1\xd8\x0b\
+\x41\xa8\x0a\x86\x0a\x9b\x71\xc7\x43\x3f\xc2\x40\xfe\x25\xd3\x51\
+\xa8\x09\x09\x21\xb4\xeb\xa6\xde\xb3\x62\xc5\xe2\x3f\x54\xb3\xdf\
+\x58\x0b\x00\xa5\xf4\xdf\xaa\xb1\x14\x50\x08\x01\x29\x6d\x84\x61\
+\x50\x71\x5b\x52\x4a\x5f\x08\x6b\xbb\x65\x89\x0d\x80\x7c\x5a\x08\
+\xf1\x80\xd6\xea\xf7\x9e\x27\xff\x58\xab\x27\xeb\x35\x8a\x5c\x2e\
+\x27\x1f\x7c\xb0\xf5\xc3\x80\xbe\x4c\x6b\x3d\x79\xd7\xef\x85\xba\
+\x80\x5d\x6f\xfa\x43\x0f\xc8\x7b\x40\x7e\x2b\xe0\x24\x01\x3b\xb9\
+\xa3\x18\x68\x9e\x6d\x21\x28\x22\x1b\xb7\x3d\x81\xbb\x1f\xfd\x1f\
+\x78\x41\x3d\xcc\x23\xa2\x46\xe4\x38\xc9\xcf\xad\x5a\xb5\xf8\x17\
+\xd5\xee\x37\xd6\x02\x20\x0c\xc3\x7f\xd8\x76\x75\x3e\x91\x6d\xbb\
+\xf2\x02\xc0\x71\x12\x7f\xbf\xf5\xd6\xa5\xaf\x8d\x28\x12\x95\xe1\
+\x9c\x73\xae\x7e\xed\x83\x0f\xaa\xef\x01\xfa\x0d\x7b\xfb\x7e\xa8\
+\x47\xfe\x70\xf6\x0b\xa5\x1f\xf9\x6d\x80\x65\x03\x56\x02\xb0\x13\
+\x80\x74\x4a\xbf\xe6\x79\x51\x34\x92\xb5\x1b\xee\xc2\x03\x4f\xde\
+\x00\xa5\x43\xd3\x51\xa8\x29\x09\x24\x12\xc9\xab\xfa\xfa\x72\x57\
+\x9a\xe8\x3d\xd6\x02\xe0\xc6\x1b\x2f\x7a\x61\xfe\xfc\x2b\x1e\x65\
+\x5b\xb9\x00\x00\x20\x00\x49\x44\x41\x54\xb7\x00\xe8\x8c\xb3\x1f\
+\x00\x88\x66\x76\x98\x4e\x46\xd0\x08\x95\x61\xe1\xc2\xab\x53\x61\
+\x18\x5e\x04\xa8\xff\x00\xe0\x8e\xf4\x3a\x5f\x8f\x6f\x1d\x76\x18\
+\x94\x7e\x78\x43\x3b\xbe\x20\x4a\xf3\x05\x2c\xbb\x34\x3a\x20\x6d\
+\x40\x5a\xa5\x9f\x0b\xb9\xe3\x47\x99\x05\x82\x0a\x01\xad\x76\xfc\
+\x37\x2c\x8d\x40\x70\xe4\xa1\xbe\x84\x2a\xc0\xfd\x4f\x2e\xc7\x33\
+\x3c\xd0\x87\x8c\x11\x70\xdd\xc4\x4f\xfa\xfa\x72\x17\x9a\x4a\x50\
+\x8d\xd9\x73\xf7\xa3\x0a\x1b\xba\x44\x31\x11\x50\x6b\x3d\xe2\x05\
+\x88\xa2\x37\x6f\xde\x95\xb3\xc3\x50\xfd\x17\x20\x0e\x19\xeb\xb5\
+\x7e\x38\x30\xb1\x3b\x79\x5d\x7a\x5c\x10\x8e\x31\x1d\x73\xac\x42\
+\x40\xeb\x52\x5b\xbb\xce\x33\x11\x12\x48\x77\xf2\xe2\x5f\x6f\x86\
+\x0a\x9b\x71\xe7\xc3\x3f\x43\xff\x30\xa7\xee\x90\x29\x02\xae\xeb\
+\x2e\x5f\xbd\x7a\xc9\xbf\x9a\x4c\x11\x7b\x01\x20\x84\xb8\x5b\x6b\
+\x1d\x7b\x01\x10\xd1\x99\x00\x89\x28\x1a\xa1\xd1\x2d\x5c\x78\x75\
+\x67\x18\xaa\x6b\x00\xbc\x77\xbc\xef\xc9\x87\x9b\x63\xfd\xdb\xaa\
+\x55\x79\x2b\xbe\xed\x14\x90\x6a\x2f\x8d\x26\x50\xfd\xd8\xb0\xf5\
+\x31\xdc\xfd\xd8\x2f\xe1\x73\x67\x3f\x32\x46\x20\x91\x70\x7f\xd8\
+\xd7\xb7\xf4\x03\xa6\x93\xc4\x5e\x00\x68\xad\xef\x89\xbb\x0f\x00\
+\x90\x52\x42\x08\x09\xad\x2b\xda\x12\x98\x8b\xcb\x62\x36\x6f\xde\
+\xd5\x3d\x61\xa8\xfe\x1b\xc0\xf4\x72\xde\x37\xec\x6d\xac\xce\x78\
+\xd5\x18\x84\x04\x92\x6d\xa5\x15\x08\x54\x4f\x34\x9e\x78\xf1\x0f\
+\xf8\xfb\x53\x7d\xd0\x68\x8c\x6d\xc3\xa9\x1e\x09\x24\x93\x89\x2b\
+\x57\xad\x5a\xf2\x59\xd3\x49\x80\xea\x7c\xa4\xc6\x72\x8c\xe1\xde\
+\x58\x96\x85\x20\x98\xf8\x3f\x6e\xad\x15\x0b\x80\x98\xf4\xf6\x5e\
+\x9b\x4d\xa5\xbc\x2b\x00\x75\xde\x44\xde\x5f\x08\xb7\x43\xc8\xd2\
+\x9d\xba\x29\x4e\x0a\x48\x75\x70\xd9\x61\xbd\xf1\xc3\x3c\x1e\x7e\
+\x7e\x05\xb6\x0c\x3e\x0d\x21\x85\xd1\xbf\x43\xd4\xcc\x04\x92\x49\
+\xf7\x0b\xab\x56\x2d\xf9\xb2\xe9\x24\x3b\xc5\xfe\x51\x76\xdd\x75\
+\x17\xae\x03\xb0\x31\xee\x7e\x80\x9d\x6b\xf5\x2b\x52\x03\xf7\x98\
+\x8d\xe7\x1d\xef\xf8\xcf\xae\x54\xca\xfb\x3b\x80\x09\x5d\xfc\x5f\
+\x26\xcc\xcc\xd4\xb6\x6c\xa0\x65\x32\x90\x9e\xc4\x8b\x7f\xbd\xd9\
+\x3e\xfc\x2c\xee\x7d\xfa\x27\xd8\x3a\xb4\x16\x42\x08\x64\xb3\x6d\
+\x90\x92\x7f\x88\x54\x5d\x42\x08\x9d\x48\x24\x3f\xbc\x6a\xd5\xd2\
+\x9a\xb9\xf8\x03\x55\xbb\xe0\xe9\x7b\x00\x31\x27\xee\x5e\x22\x28\
+\x00\xf8\x44\x37\x42\xa5\x19\xfe\xea\x4a\xa5\xf0\x31\x44\xb0\x18\
+\x4f\x49\x1f\x22\xac\xde\x1f\x91\x10\xa5\x5d\x07\x93\xd9\xaa\x75\
+\x49\x11\xd1\x00\x9e\xdd\x7c\x17\xd6\x6e\xfc\x13\xf4\x2e\xb3\x3b\
+\xa4\xb4\x90\xcd\xb6\x63\x60\x60\x3b\xc2\x90\x4b\xff\x28\x7e\x52\
+\xda\x85\x96\x96\x44\xcf\x4d\x37\x2d\xfa\xbd\xe9\x2c\x7b\xaa\x52\
+\x01\x20\xef\x04\x74\xec\x05\x40\xa5\x95\xbd\xd6\x9a\x2b\xc6\x23\
+\x32\x6f\xde\xd7\x8e\x0a\xc3\xf0\x17\x00\x8e\x8f\xaa\x4d\x85\x3c\
+\x2c\x54\x67\xa5\xa6\xb3\x63\x92\x1f\x67\xf8\xd7\x9f\xa2\x3f\x88\
+\x47\x5e\x58\x81\x6d\xc3\xcf\xee\xf5\xfb\xa5\x22\xa0\x03\x83\x83\
+\xfd\xf0\x7d\xee\xd6\x4d\xf1\x71\x1c\xe7\xb9\x4c\xc6\x7e\xdd\xf2\
+\xe5\x8b\xaa\x32\x0a\x5e\xae\xaa\x14\x00\x42\xa8\x3b\xaa\x73\x6d\
+\xad\xb4\x8f\x6a\xec\x5b\xd8\xf8\xe6\xcd\xbb\xea\xff\x09\xa1\xfe\
+\x0b\x40\x3a\xca\x76\x8b\x6a\x1b\xd2\xe8\x88\xb2\xc9\x57\xb1\x5d\
+\x20\xd1\x5e\xfa\x2f\xd5\x9f\x4d\x03\x8f\xe3\xb1\xf5\xb7\xc2\x1f\
+\x63\x57\x3f\x21\x04\x5a\x5b\xb3\xc8\xe7\xf3\xc8\xe7\x87\xc1\x53\
+\xff\x28\x5a\x02\xae\xeb\xde\xe9\x79\xf2\xad\xcb\x97\xe7\x2a\xdf\
+\xa2\x36\x26\x55\x29\x00\x7c\x5f\xfd\xc5\xb6\xad\x10\xb1\x0f\xb1\
+\x57\xfa\x8f\x98\x23\x00\x95\x98\x37\xef\xf2\x49\x42\xb8\xff\x0d\
+\xe8\x73\xe3\x68\x7f\x38\xdc\x88\x34\xe2\x39\x25\xd3\x72\x80\x44\
+\xb6\x74\xe7\x4f\xf5\x47\xe9\x00\x4f\x6d\xfc\x23\x9e\xdf\xf2\xd7\
+\x32\xde\x25\x90\x4a\xa5\x61\xdb\x36\x86\x86\x06\xa0\x14\x67\x07\
+\x52\xe5\x76\x3c\xef\x5f\xba\x6a\x55\x2e\x67\x3a\xcb\x58\xaa\x32\
+\x1b\xe6\xc6\x1b\x2f\x1a\x00\xf0\x70\x35\xfa\xaa\x10\x0b\x80\x09\
+\x5a\xb0\xe0\x8a\x53\x84\x70\xef\x03\x10\xcb\xc5\x1f\x00\x06\xbd\
+\xe7\x23\x6f\xd3\xb2\x4b\x9b\xf9\x64\xa6\xf1\xe2\x5f\xaf\x06\xf2\
+\xeb\x71\xef\x53\x3f\x29\xf3\xe2\xff\x0a\xc7\x71\xd1\xde\x3e\x09\
+\xc9\x64\x0a\xfc\x08\xa0\x4a\x58\x96\xbd\x3d\x9d\x76\x4e\xab\x87\
+\x8b\x3f\x50\xdd\x59\xef\x77\x02\x38\x36\xce\x0e\x74\x35\x8e\x1e\
+\xa4\x57\x59\xb0\xe0\xca\xf3\xb4\xc6\x37\x30\xca\x56\xbe\x51\xe8\
+\xf7\x9e\x2f\x6d\xd5\x14\xc1\x1f\xb3\xe5\x02\x89\x0c\xe0\x44\xfa\
+\x90\x82\xaa\x49\x43\xe3\x99\x4d\x7f\xc1\xba\x4d\x77\x54\xba\xff\
+\x07\x00\x20\x9d\xce\x20\x91\x48\x62\x68\x68\x00\x41\x50\xb3\xa3\
+\xb6\x54\x93\x04\x5c\xd7\xbd\x75\xf3\xe6\xe9\x67\xde\x7b\xef\x47\
+\x7c\xd3\x69\xc6\xab\x8a\x05\x80\xbe\x13\x10\x1f\x8a\xb5\x87\x0a\
+\x0b\x00\x4e\x02\x2c\xcf\xfb\xde\x97\x4b\x6e\xdf\x9e\xf9\x96\xd6\
+\xa8\xca\x8e\x56\x4a\x7b\x10\x32\x84\xae\x60\x25\x80\x93\x04\x12\
+\xad\xa5\x03\x83\xa8\x7e\x0d\x7b\x9b\xf1\xe8\x0b\xab\xd0\x9f\x5f\
+\x1f\x69\xbb\x96\x65\x23\x9b\x6d\x87\xe7\x79\xc8\xe7\x87\xb8\x52\
+\x80\xc6\x24\xa5\x55\x74\xdd\xc4\xfb\x4d\x9c\xe6\x57\xa9\xaa\x15\
+\x00\x96\x25\xee\x88\xfb\xdf\x12\x9f\xe1\x55\xcf\xbc\x79\x57\x1d\
+\x3e\x30\xa0\x7f\x2d\x04\xaa\x7a\x7a\x62\x28\x86\x21\xd1\x5a\xd6\
+\x7b\x84\x00\x9c\x16\x20\xd1\x52\x3a\x21\x90\xea\x97\xd6\x0a\xcf\
+\x6e\xb9\x07\xeb\x5e\xba\x3d\xc6\x13\xfc\x04\x5c\x37\x01\xd7\x4d\
+\xa0\x58\x2c\x20\x9f\x1f\x86\x52\x2c\x04\xe8\xd5\x5c\x37\x71\x97\
+\x65\xc9\xd9\x2b\x57\x2e\xee\x37\x9d\x65\x22\xaa\x56\x00\x2c\x5b\
+\xf6\xef\x0f\x2f\x58\x70\xd5\x56\xad\xe3\x9b\xc6\x1d\xc5\x30\x20\
+\x8d\x6d\xde\xbc\x2b\x67\x4b\xa9\x7f\x15\xe7\x9f\xe5\x48\x0a\x7a\
+\x13\xd2\xe3\x2c\x00\x6c\xb7\x74\xe1\x77\xd3\xe0\xa3\xdd\x06\x30\
+\x5c\xdc\x8c\x47\x5e\x5c\x85\x81\x88\xef\xfa\x47\x93\x48\x24\x91\
+\x48\x24\x51\x2c\x16\x50\x28\xe4\x2b\x3e\x72\x9c\x1a\x83\x65\xd9\
+\x83\x89\x44\xe2\x23\x2b\x56\x2c\xfa\xb9\xe9\x2c\x95\xa8\xe2\x96\
+\x58\x42\x2b\x25\x62\xdd\x16\x98\x23\x00\xf1\x5b\xb0\xe0\xca\xf3\
+\x84\xc0\x2d\x26\x2e\xfe\x00\x30\x10\x3c\x33\xea\xf7\x85\x55\x1a\
+\xe2\x6f\xdd\x07\x68\x99\xba\x63\xcf\x7e\x5e\xfc\xeb\x9a\xd6\x0a\
+\xcf\x6c\xbe\x0b\xf7\x3e\xfd\xd3\xaa\x5e\xfc\x77\x95\x48\x24\xd1\
+\xd6\xd6\x81\x6c\xb6\x1d\xae\x9b\x00\xff\x52\x35\x27\x21\x84\x76\
+\xdd\xc4\xf2\x30\x74\x3a\xea\xfd\xe2\x0f\x54\x79\xeb\x5b\x21\xd4\
+\x1d\x80\xe8\x8a\xa3\x6d\xa5\x14\x27\x01\xc6\x68\xd6\xac\x9c\x3d\
+\x69\x52\xeb\x55\x5a\xeb\xf3\x4d\xe6\xd8\x52\x78\x14\xd3\x52\xa7\
+\xed\xf6\x35\x69\x95\x66\xf0\x3b\x29\x3e\xdb\x6f\x34\x03\xf9\xf5\
+\x78\x6c\xfd\xad\x18\x2c\xd4\xc6\x3e\x2a\xb6\xed\x20\x93\x71\x10\
+\x86\x21\x0a\x85\x3c\x3c\xaf\xc8\x91\xc7\x26\xe1\x38\xee\xe3\x99\
+\x8c\x75\xd6\xf2\xe5\xb9\xc7\x4c\x67\x89\x4a\x95\x0b\x00\x79\x57\
+\x5c\x17\xe9\x68\x86\xe6\x04\x2b\x88\xbd\x38\xf3\xcc\x2f\x77\xb8\
+\xae\xb3\x4c\x6b\x7d\xba\xe9\x2c\xc5\x60\x00\xc2\x09\x60\x3b\x36\
+\xec\x04\x60\x27\x00\xc9\x13\x1c\x1a\x8e\xd2\x3e\xd6\xbd\x74\x27\
+\x9e\xdd\x7c\xf7\x6e\x5b\xf9\xd6\x0a\xcb\xb2\xd0\xd2\x92\x41\x4b\
+\x4b\x06\xbe\xef\xa1\x58\x2c\xc0\xf7\x3d\xde\x84\x34\x20\xdb\x76\
+\xb6\x48\xe9\x7c\x66\xf5\xea\xc5\x3f\x36\x9d\x25\x6a\x55\xfd\xe8\
+\x94\xd2\xb9\x3b\x0c\xe3\xd9\x7a\x33\x8a\xd9\xba\x42\xd4\xe0\x27\
+\x8d\x61\x67\x9f\xfd\xd5\xfd\x6c\xdb\x5a\x81\x08\xb7\xf4\xad\xd4\
+\x70\xf2\xd1\xff\xbf\xbd\xbb\x8f\x8e\xb3\xac\xf3\x06\xfe\xfd\xdd\
+\x2f\x93\xa6\xaf\xd0\xb2\xf8\x0e\xb8\x2e\xbb\xa0\xa2\x3e\x0a\xe8\
+\x79\x76\x45\x74\x85\x3d\x6c\x1f\x81\x4c\x88\xbb\x7a\x44\xc5\x75\
+\x59\xde\xac\x36\x49\x2b\x2b\xd2\x06\xf1\x05\x6c\x5a\x11\x1f\xcf\
+\x4a\x7d\x59\x14\x14\x9f\x9d\x4e\x92\xd2\xd2\x34\xa1\x95\x22\x82\
+\x14\x10\x90\x42\xdb\x43\xa5\x85\x52\xe8\x6b\xda\x24\x33\x93\xc9\
+\xcc\xdc\xf7\xfd\x7b\xfe\x48\x5b\x4a\xe9\x4b\x26\xb9\x67\xae\xb9\
+\x67\xbe\x9f\x73\x38\x9c\x26\x93\xfb\xfe\x72\x1a\xe6\xfa\xcd\x75\
+\x5f\xd7\xef\xc2\x9b\xa7\xbd\xc7\x74\x0c\x2a\x91\xbe\xd4\x66\x6c\
+\xda\xb1\x1a\x39\x2f\x1a\xeb\xaa\x5c\x37\x06\xd7\x8d\x41\x55\xf7\
+\x17\x03\x39\x14\x0a\x39\xd3\xb1\x68\x9c\x1c\xc7\xce\x58\x96\xfb\
+\x83\xde\xde\x9b\x6e\x34\x9d\xa5\x54\xca\x7a\x2c\x56\x22\x31\x6b\
+\x37\x80\x23\x37\xe8\x1e\xa7\x70\x66\x00\x38\xfe\x1f\xaa\xb1\x71\
+\xd1\x7b\x1c\xc7\x7e\x14\x15\x34\xf8\x03\x40\x7f\xa6\x24\xbf\x42\
+\x64\x58\xae\x90\xc6\xfa\x57\x96\xe1\xd9\x6d\x9d\x91\x19\xfc\x0f\
+\x25\x32\xb2\x7b\x60\xca\x94\xa9\x38\xe1\x84\x19\x98\x34\x69\x0a\
+\xd7\x0b\x44\x90\x6d\xdb\xf9\xba\xba\x89\x0b\x57\xad\x8a\x4d\xad\
+\xe6\xc1\x1f\x30\x73\xfc\xed\x9f\x00\xbc\x23\xec\x8b\x86\xd3\xb8\
+\x83\x8f\x00\x0e\xb8\xec\xb2\x05\xe7\x07\x41\xd0\x09\xe0\x04\xd3\
+\x59\x0e\xc7\x02\xa0\xba\x28\x02\x6c\xeb\x7b\x12\x2f\xed\x79\x04\
+\x7e\x10\x99\x1e\x2a\xc7\x64\x59\xd6\xc1\x1d\x04\xaa\x0a\xcf\x2b\
+\xc0\xf3\xf2\xc8\xe7\x0b\xdc\x49\x50\xa1\x2c\xcb\x2a\x38\x4e\xec\
+\xae\x69\xd3\xe4\xea\x44\x62\x7e\x4d\x9c\x12\x65\xaa\x00\x08\xb5\
+\x5d\xac\xaa\x86\xd4\xb0\x83\x05\x00\x00\xc4\xe3\xed\x97\x05\x01\
+\xee\xc6\x48\xdf\xbd\x8a\x93\xf3\x06\x31\x5c\xe8\xc7\x04\xb7\xe2\
+\x6a\x13\x2a\xd2\xbe\xcc\x8b\xd8\xb4\xe3\x01\x64\xf3\x7b\x4d\x47\
+\x29\x19\x11\x39\xf8\x98\xa0\xbe\x1e\x08\x02\x1f\x85\xc2\x48\x41\
+\x50\x28\x14\xb8\x7b\xc9\x30\xdb\xb6\x87\x6c\x3b\x76\x47\x3e\x8f\
+\xb9\xbd\xbd\x95\x7b\x70\x4f\x29\x94\xbd\x00\x10\x91\x27\xc3\x5e\
+\x28\x53\x28\x14\x10\xd2\xf4\x7d\xcd\x17\x00\xf1\xf8\x82\xcf\x02\
+\xf8\x25\xcc\x14\x87\xa3\xd6\x97\xda\x8c\xb7\x4d\xff\xa0\xe9\x18\
+\x34\x46\xd9\x7c\x3f\xb6\xec\x7e\x08\xbb\x07\xab\x66\x41\xf5\xa8\
+\x59\x96\x8d\xba\x3a\x1b\x75\x75\x23\x47\x5b\x07\x41\x00\xcf\xf3\
+\xe0\x79\xf9\xfd\x33\x05\x3e\xf8\x56\x54\x7a\x8e\xe3\x0c\x5a\x96\
+\x73\x7b\x6f\xaf\xcc\x07\xda\x6a\xb2\x0a\x2b\xfb\x9b\xbc\xaa\x3e\
+\x17\xf6\x35\x3d\x2f\xac\xd9\x1a\xa9\xc9\x5f\x82\x03\xf6\xf7\xf4\
+\xff\x2f\x94\x79\x6d\xc8\x58\xec\x49\xbd\xc0\x02\x20\x82\xfc\xa0\
+\x80\x6d\x7b\x9f\xc0\xd6\x3d\x8f\x21\xd0\x9a\xfa\xb0\x75\x54\x96\
+\x65\x21\x16\x8b\x21\x16\x1b\x39\x4a\x63\xe4\x91\x81\xb7\xbf\x18\
+\xf0\x10\x04\x1e\x7c\x3f\x00\x8b\x82\x70\xb8\x6e\x6c\xab\x6d\xdb\
+\x37\xac\x5c\xd9\x76\xb7\xe9\x2c\xa6\x95\xbd\x00\xe8\xe8\x68\xd9\
+\x1a\x8f\x2f\x4c\x01\x45\xf6\x73\x3d\x86\x91\x19\x80\xf1\xb3\x2c\
+\xd4\xc4\x73\x9f\x23\x69\x6c\x5c\x78\xb5\xaa\xfe\x18\x11\x59\xb1\
+\x34\x30\xb4\x0d\x5e\x90\x83\x63\x55\xe4\x53\x0a\x7a\x03\xc5\xae\
+\xc1\x8d\xd8\xbc\xeb\x21\xe4\x0a\x29\xd3\x61\x2a\xda\xc8\x23\x03\
+\x17\xae\xfb\x5a\xdf\x6a\x55\x45\x10\xf8\xf0\x7d\x0f\x9e\x37\x52\
+\x10\xf8\x3e\x1f\x1f\x8c\x96\x65\x49\xe0\x38\xb1\xc7\x2c\x4b\x67\
+\xad\x5c\x79\x73\x49\x1b\xd2\x45\x89\x81\x69\x5e\x51\xa0\x7d\x23\
+\x80\x73\xc2\xb8\xda\x81\xff\x29\xc2\x20\x22\x35\xb9\x77\x27\x1e\
+\x6f\x9f\xab\xaa\xb7\x9a\xce\x51\x0c\x45\x80\xbe\xd4\x5f\xf0\x26\
+\x6e\x07\xac\x78\xfb\x32\x5b\xb1\x79\xd7\xef\x91\x1e\xde\x69\x3a\
+\x4a\x64\x89\x08\x6c\xdb\x81\x6d\x3b\x88\x1d\x72\xe6\xa6\x6a\x00\
+\xcf\xf3\xe1\xfb\x05\xf8\xbe\x8f\x20\xf0\x11\x04\x01\x0f\x31\x02\
+\x00\x08\x1c\xc7\xde\x6b\xdb\xee\x4f\xa7\x4e\xc5\xbc\x44\xa2\xad\
+\x66\x3f\xe0\x1d\x8d\xa9\xe7\xbc\xcf\x21\xa4\x02\xa0\x50\x08\xef\
+\xef\x54\x15\xd9\xd0\x2e\x16\x11\x0d\x0d\xed\xb3\x01\x44\x6a\xf0\
+\x3f\x60\xe7\xc0\x06\x16\x00\x15\x6c\x28\xbf\x17\x2f\xee\x7e\xb8\
+\x26\x9f\xf3\x97\x8b\x88\x05\xd7\xb5\x5e\x37\x5b\x00\x00\xaa\x23\
+\xc5\xc1\xc8\x07\xa4\x91\xa2\xe0\x40\x71\x70\xe0\x6b\xd5\xca\xb2\
+\xac\xc0\xb6\xdd\x27\x5d\xd7\xba\x71\xc5\x8a\xb6\x95\xa6\xf3\x54\
+\x32\x23\x05\x80\xaa\x6e\x14\x09\x67\xa6\x39\x97\x0b\xef\x43\xbb\
+\x65\x59\x43\xa1\x5d\x2c\x02\xe2\xf1\x05\xff\x06\x60\xa1\xe9\x1c\
+\x63\xb5\x2f\xb3\x15\x79\x2f\x8d\x98\x33\xd9\x74\x14\x3a\x44\xc1\
+\xcb\xe2\xa5\xbe\x47\xf1\xea\xbe\xa7\xd9\x26\xd7\x10\x91\x91\xe2\
+\xc0\xb2\x2c\x38\xce\x91\x8f\xc0\x1c\x29\x06\x82\xfd\x85\xc2\xa1\
+\xff\xd6\xfd\xdf\xd3\x83\x45\x44\xe5\x13\xb8\xae\xb3\xdd\xb6\x9d\
+\x5f\x4e\x99\x32\xf5\x5b\x89\x44\x73\xcd\x7d\x98\x1b\x0b\x23\x05\
+\x80\x65\x59\xaf\x84\xb1\x13\x60\x64\xaa\x2b\xcc\x85\x44\x9a\x09\
+\xf1\x62\x15\xad\xb1\xb1\xfd\x0b\xaa\x58\x8c\x88\x3c\xf3\x3f\x32\
+\xc5\x8e\xfe\xe7\x70\xca\x49\x1f\x36\x1d\x84\x00\x14\xfc\x61\xbc\
+\xb2\xf7\x4f\x78\xb9\xef\x4f\x08\xb4\x3a\xf6\xf3\x57\x33\xcb\x1a\
+\x29\x10\x46\xeb\xd0\x82\x41\x55\xf7\xff\x13\x1c\x9c\x6d\x38\xf4\
+\x6b\x80\x1c\x5c\x9f\x30\xf2\x5e\xaf\x07\xdb\x24\x87\xb9\x0b\xcc\
+\xb6\xed\xac\xe3\xc4\x7a\x27\x4e\xc4\xdc\x6a\xea\xd1\x5f\x2e\x86\
+\x66\x00\xf0\x4a\x18\xd7\x29\x14\x72\xa1\xfe\x32\xa9\x4a\x3a\xb4\
+\x8b\x55\xb0\xc6\xc6\xf6\xcf\xa8\xe2\xe7\x88\xc0\x6a\xff\xe3\x79\
+\xb5\xff\x69\xbc\xe3\xa4\x73\x20\xd1\xff\x4f\x89\x2c\x3f\x28\xe0\
+\x95\x7d\x4f\x61\x5b\xdf\xe3\x28\xf8\xc3\xa6\xe3\x50\x89\x14\x5b\
+\x30\x1c\x9f\xe2\xf5\x6f\xdf\x3a\xca\xf7\x73\x59\x0f\x04\x2b\x55\
+\xf3\x5d\x4b\x97\xce\x7b\x28\xc4\x40\x35\xc7\x58\x01\x10\xc6\x13\
+\x80\x30\xa7\xff\x01\xc0\xb2\x64\x20\xd4\x0b\x56\xa0\x78\x7c\xe1\
+\xc7\x55\xf5\xbf\x01\xd8\xa6\xb3\x84\x21\x57\x48\xa3\x2f\xf5\x02\
+\x4e\x9a\x72\xba\xe9\x28\x35\x27\xd0\x02\x5e\xdd\xb7\x0e\x2f\xf7\
+\xad\x45\xde\xab\xa9\xa7\x67\x14\x0a\xc1\xeb\xc7\x81\xc3\xff\xfc\
+\x1a\x55\xac\x17\xd1\x84\x88\xfc\x36\x99\x6c\xdd\x58\x8e\x74\xb5\
+\xc0\x48\x01\xe0\x38\x13\x5e\xf5\xfd\xf1\x3d\xa2\x09\x02\x1f\x9e\
+\x17\xee\x34\x63\x10\x68\x55\x17\x00\x97\x5c\xb2\xe8\x2c\x20\xe8\
+\x40\x85\x76\xf8\x1b\xab\xad\x7d\x6b\x31\x63\xca\xe9\x51\x7e\x96\
+\x11\x29\x7e\x50\xc0\xf6\xfe\x75\x78\xb9\xef\x31\xe4\xbd\x9a\x79\
+\x6a\x46\x65\x76\x60\xd0\x57\xb5\x7e\xd3\xd9\xd9\xc2\xe9\xfd\x12\
+\x30\x52\x00\x24\x12\xd7\xa6\xe3\xf1\xf6\x02\x80\x23\xaf\x4e\x19\
+\x85\xe1\xe1\xf0\xa7\x1a\x2d\xcb\xae\xda\x7e\xa4\x97\x5e\xfa\x83\
+\xd3\x2c\xcb\xef\x41\x05\xf6\xf6\x1f\xaf\x54\x76\x27\xfa\x33\x2f\
+\xe2\xc4\x49\xa7\x99\x8e\x52\xd5\x54\x7d\xec\x18\x78\x0e\x2f\xee\
+\x7e\x84\x03\x3f\x95\xc4\x6b\x9f\xf4\xf5\xd7\x1d\x1d\x73\x37\x99\
+\xce\x53\xed\x4c\xb6\x7b\x1d\xf3\xf2\x60\x55\x45\x2e\x17\xfe\x22\
+\x4f\x11\xdd\x1c\xfa\x45\x2b\x40\x53\xd3\xa2\xe9\xbe\xef\x77\x03\
+\x78\x8b\xe9\x2c\xa5\xf2\xe2\xee\x47\x70\xc2\xa4\xd3\x38\x0b\x50\
+\x02\x81\xfa\xd8\xbe\x6f\x1d\xb6\xf6\xad\x45\xde\xab\x89\x65\x32\
+\x54\x3e\x39\x55\x79\x50\x44\x97\xdb\xb6\xb7\x34\x91\xb8\x7e\xab\
+\xe9\x40\xb5\xc4\x60\x01\x20\xfe\x58\x5b\x5b\xe6\xf3\xe1\x2e\xfe\
+\x3b\xc0\xb2\x50\x75\xd3\x4c\xe7\x9f\xdf\xe6\x78\x5e\xf0\x3f\x22\
+\x38\xc3\x74\x96\x52\x1a\xcc\x6e\xc7\xee\xc1\x8d\x38\x79\x6a\x55\
+\xff\x67\x96\x55\xa0\x1e\x76\xf4\x3f\x87\xad\x7b\x1e\x8b\xe4\xf1\
+\xbc\x54\xb1\x76\x01\xe8\x51\x95\x65\xc3\xc3\x6e\x4f\x77\xf7\x2c\
+\xfe\x72\x19\x62\xb0\x00\xd0\x31\x6f\x2e\x1d\x1e\x2e\xcd\x16\x4f\
+\xcb\x9a\xba\xae\x24\x17\x36\x68\xc6\x8c\xc9\xb7\xa9\xe2\x1f\x4d\
+\xe7\x28\x87\xcd\xbb\x7e\x8f\x93\xa6\xbc\x0b\x96\x8c\xf9\xc9\x12\
+\x01\xf0\xfc\x3c\x76\x0c\x3c\x8b\x6d\x7b\x1f\x47\xae\xc0\x4f\xfc\
+\x34\x6e\x81\x08\x9e\x02\x64\x55\x10\xe8\xf2\xce\xce\x96\x87\x79\
+\xf2\x6a\x65\x30\xf9\x08\x60\x4c\xb3\xb5\x85\x42\xbe\x24\xe7\x69\
+\x8b\x08\x96\x2f\x6f\x0e\x65\x7b\x62\xa5\x68\x68\x58\x70\x85\x2a\
+\xae\x35\x9d\xa3\x5c\x72\x85\x14\x5e\xdc\xfd\x47\xfc\xf5\xc9\xe7\
+\x99\x8e\x12\x49\x39\x6f\x10\xdb\xfa\x9e\xc4\xf6\xfe\x67\xe0\x07\
+\xdc\xc7\x4f\xe3\x92\x11\xc1\x03\x00\x96\xa9\xda\xcb\x92\xc9\xd9\
+\xdb\x5f\xfb\x56\xab\xb1\x50\xf4\x7a\x46\x0a\x80\xa6\xa6\x45\xf5\
+\xbe\x1f\x8c\xa9\x7d\xdb\xf0\x70\x69\xb6\x1b\x89\x48\x55\xbd\xe3\
+\xc5\xe3\xed\xe7\x01\xb8\xc3\x74\x8e\x72\x7b\xb9\xef\x09\x4c\x9f\
+\xfc\xd7\x38\x61\xe2\xdb\x4d\x47\x89\x8c\xf4\xf0\x1e\x6c\xdb\xfb\
+\x38\x76\x0d\x6c\x84\x8e\x7d\x69\x0e\xd5\x36\x1f\xc0\x93\x00\xee\
+\x07\xd0\xb3\x77\x6f\xfa\x91\x35\x6b\xda\x78\xdc\x63\x85\x33\x52\
+\x00\x04\x81\xf7\xf6\xb1\xf4\xa0\xf1\x7d\x0f\x85\x42\x69\x7e\xa7\
+\x44\xac\xaa\x79\x0e\xd5\xd0\xb0\xe0\x64\x00\xf7\x60\x1c\xbb\x2c\
+\xa2\x4b\xf1\xfc\xf6\x1e\x7c\xe8\x9d\x97\xc3\xb6\x62\xc7\x7f\x79\
+\x0d\x1b\x18\x7a\x19\x2f\xf7\x3d\x8e\xbd\xe9\x2d\x3c\x68\x96\xc6\
+\x62\x3b\x80\x55\xaa\xb2\xcc\x71\x64\x75\x22\xd1\x5c\xb5\xbb\xa8\
+\xaa\x95\xa1\x02\xc0\x3a\x6b\x2c\x8d\x80\xb2\xd9\x21\x94\xea\x4c\
+\x6c\xdb\xb6\x76\x94\xe4\xc2\x65\xd6\xd6\xd6\x66\x3d\xf3\x8c\xdc\
+\x0d\xe0\xad\xa6\xb3\x98\x92\xcd\xf7\x63\xc3\xab\x2b\xf0\xde\xb7\
+\x5f\x82\x48\x77\x3a\x2e\x01\x45\x80\x3d\x83\x7f\xc1\xb6\xbd\x8f\
+\x63\x30\x5b\x15\xbf\xf2\x54\x3e\x19\x00\x7f\x54\xd5\x55\xaa\xb2\
+\xaa\xab\xab\xf5\x4f\xa6\x03\xd1\xf8\x18\x3a\x0b\x40\xce\x2d\x76\
+\x15\xbf\xef\xfb\xc8\xe7\x4b\x77\x5a\xaf\x88\xbc\x58\xb2\x8b\x97\
+\xd1\x33\xcf\x4c\x6a\x03\x70\x81\xe9\x1c\xa6\xf5\xa5\x5e\xc0\x96\
+\x5d\x0f\xe3\x9d\x27\xff\x83\xe9\x28\x15\x61\xb8\x30\x88\xed\xfb\
+\x9e\xc1\x8e\x81\x67\xb9\x87\x9f\x46\xcb\x17\xc1\xd3\x80\xac\x02\
+\x82\x55\x96\x95\xf9\x3d\x8f\xd4\xad\x2e\xa6\x4e\x03\x9c\x59\xec\
+\xcf\x64\xb3\xa5\x7d\xd3\x12\xb1\xd6\x97\xf4\x06\x65\xd0\xd0\xd0\
+\x7e\x01\x80\x1b\x4c\xe7\xa8\x14\x5b\xfb\xd6\xc2\xb1\x27\xe0\x1d\
+\x33\xce\x36\x1d\xc5\x10\xc5\xbe\xcc\x56\x6c\xef\x7f\x06\x7b\x52\
+\x7f\xe1\xc9\x7c\x74\x3c\x0a\x60\xbd\x88\xac\x56\xc5\xea\x6c\xd6\
+\x5d\xc3\x2d\x7a\xd5\xad\xec\x05\x40\x63\xe3\xa2\xb3\x55\x83\xf7\
+\x16\xf3\x33\x9e\x57\x40\x3e\x5f\xea\xc2\x53\x7a\x4a\x7c\x83\x92\
+\x9a\x39\xf3\x7b\x27\x8a\xe0\x17\xa8\x82\x03\x7e\xc2\xb4\x65\xd7\
+\x83\x70\xec\x18\xde\x72\xc2\xfb\x4c\x47\x29\x9b\xbc\x97\xc1\xf6\
+\xfe\x75\xd8\xbe\x6f\x1d\xf7\xef\xd3\xf1\x6c\x17\xc1\x1f\x00\xac\
+\x52\xf5\x57\x74\x74\x7c\x7d\x9b\xe9\x40\x54\x3e\x65\x2f\x00\x54\
+\x83\xa2\xf7\x80\x94\xf2\xd9\xff\x7e\x3a\x3c\xac\x0f\x96\xf2\x06\
+\xa5\x16\x8b\xb9\x3f\x01\xc0\xa5\xef\x87\x51\x00\x9b\xb6\xdf\x8f\
+\xbc\x37\x84\x53\x4e\xfa\x48\x15\xaf\x08\x18\xf9\xb4\xff\xea\xbe\
+\x3f\xa3\x2f\xf5\x02\x57\xf3\xd3\xd1\xec\x12\xc1\x83\x00\x56\x01\
+\xf6\xaa\x64\x72\x76\x55\x76\x3f\xa5\xd1\x29\xeb\xfb\xe1\x25\x97\
+\x2c\x3a\xcb\xb6\x83\xa7\x51\xc4\xa7\xd4\x42\x21\x8f\x54\xaa\xb4\
+\x67\xf4\xd8\xb6\x33\xb0\x7a\xf5\x77\x22\xdb\x23\xbf\xb1\xb1\xfd\
+\x0b\xaa\xb8\xd3\x74\x8e\x4a\xf7\xa6\x69\xef\xc6\xdf\xbe\xe5\x02\
+\x58\x62\xb2\xfd\x45\xb8\xd2\xc3\x7b\xb0\x6b\x70\x3d\x76\x0d\x6e\
+\x44\xae\x90\x32\x1d\x87\x2a\x4f\x1a\xc0\xa3\xaf\x2d\xdc\x6b\x79\
+\x92\x4d\x78\xe8\x80\xb2\xbe\x13\xda\x76\xf0\x6d\x14\x35\x45\xad\
+\x18\x1a\x2a\x7d\x27\x32\xcb\xb2\x5f\x2c\xf9\x4d\x4a\x24\x1e\x6f\
+\x3f\x55\x15\x3f\x34\x9d\x23\x0a\x76\x0e\xac\x47\x2a\xbb\x13\x67\
+\xbe\xed\x9f\x31\x79\xc2\xc9\xa6\xe3\x8c\xd9\x70\x61\x00\xbb\x07\
+\x9f\xc7\xce\x81\x0d\xc8\xe4\x76\x9b\x8e\x43\x95\x25\x0f\xe0\x0f\
+\x22\xb8\x5f\x15\xab\x6d\xfb\x94\x27\x13\x89\x4f\x1f\xd2\x75\x95\
+\x4d\x78\xe8\x35\x65\x2b\x00\xe2\xf1\xf6\x73\x00\x7c\xaa\x98\x9f\
+\xc9\xe5\x72\xf0\xfd\x31\x77\x0c\x1e\x35\xdb\xb6\x7a\x4b\x7e\x93\
+\xd2\xf9\x11\x80\x69\xa6\x43\x44\xc5\x50\xbe\x0f\x4f\xbd\xf8\x1b\
+\xbc\x63\xc6\x39\x38\xe5\xa4\x73\x23\xd3\x36\x38\x9b\xdf\x8b\xdd\
+\x83\x9b\xb0\x3b\xb5\x09\xe9\xe1\x9d\xa6\xe3\x50\x65\xd9\x8c\x91\
+\xfd\xf8\xab\xd8\x5b\x9f\x8a\x51\xce\x19\x80\x5b\x50\xc4\x23\x07\
+\x55\xc5\xd0\x50\x39\xb6\x2b\x09\x6c\x1b\x3f\x29\xc3\x8d\x42\xd7\
+\xd8\xd8\xfe\x19\xd5\xe2\x8a\x2a\x1a\x39\xdd\xee\xa5\x3d\x8f\x62\
+\x7b\xff\xb3\x78\xe7\x5f\xfd\x3d\xde\x34\xed\x4c\x88\xd8\xa6\x63\
+\xbd\x4e\xa0\x3e\x06\x86\xb6\x61\x6f\x7a\x0b\xf6\x66\xb6\x60\x28\
+\xc7\x1e\x2b\x74\xd0\x30\x80\xd5\x80\x2c\x0b\x02\xab\xa7\xab\x6b\
+\xf6\x8b\xa6\x03\x51\x34\x95\x65\x0d\xc0\xfe\xb6\xb4\x45\x2d\xb2\
+\xcb\x64\xd2\x25\x39\xf2\xf7\x70\xb6\xed\xa4\x57\xaf\xfe\xce\x94\
+\x92\xdf\x28\x64\x23\x47\xfc\x06\xeb\x01\xbc\xc9\x74\x96\xa8\xab\
+\x73\xa7\xe0\x6d\x27\x7e\x10\x6f\x9e\xf6\x1e\xb8\x4e\xbd\x91\x0c\
+\x0a\x45\x66\x78\x17\xfa\x33\xdb\xd0\x3f\xf4\x32\xf6\x65\xb6\x22\
+\xd0\xaa\xea\x4e\x4d\xe3\x22\x43\x22\xfa\xbb\x20\x90\xc4\xf0\xb0\
+\xdb\xc5\x4f\xf9\x14\x86\x72\xcd\x00\xdc\x5a\xcc\x8b\x3d\xaf\x50\
+\x96\xc1\x1f\x00\x1c\xc7\x7e\xbc\x2c\x37\x0a\x99\xe7\x05\x0b\x44\
+\x38\xf8\x87\x21\x57\x48\x61\xf3\xae\x07\xb1\x65\xd7\x43\x98\x3e\
+\xf9\x34\x9c\x3c\xed\x0c\x9c\x30\xf1\x54\xc4\x9c\x89\x25\xbb\x67\
+\xde\x1b\x42\x7a\x78\x27\x52\xc3\x3b\x91\xca\x6e\x47\xff\xd0\x36\
+\xf8\x01\x7b\xac\xd0\xeb\xec\x11\x91\x4e\x00\x5d\x43\x43\xee\xea\
+\xee\xee\x59\xa5\xeb\x84\x46\x35\xa9\xe4\x05\x40\x3c\xbe\xf0\x62\
+\x40\x3f\x52\xcc\xcf\x94\x63\xe1\xdf\x01\x8e\x63\x7d\xb3\x6c\x37\
+\x0b\x49\x3c\xbe\xf0\x23\x80\x5e\x61\x3a\x47\xb5\x51\x04\xe8\x4b\
+\x6f\x46\x5f\x7a\x33\x04\x40\x7d\xdd\x0c\x9c\x30\xf1\xed\x98\x54\
+\x77\x32\x26\x4d\x98\x81\x89\xb1\xe9\x70\xed\xd1\xcf\x10\xf8\x41\
+\x01\x79\x2f\x83\xe1\xc2\x20\xb2\xf9\x7d\xc8\xe6\xf7\x61\x28\xdf\
+\x87\x4c\xae\x8f\x2b\xf6\xe9\x68\xb2\x22\x58\x1d\x04\xf2\x2b\xc7\
+\x49\x2d\x65\xe7\x3d\x2a\xa5\x92\x16\x00\x6d\x6d\x6d\xd6\xba\x75\
+\x7a\x53\x31\x5d\x7f\x87\x87\xb3\xf0\xbc\xf2\x1c\x22\xe5\xba\xee\
+\xee\xfb\xee\x6b\x7b\xa4\x2c\x37\x0b\x8d\x0a\xb0\xf0\x87\x60\x93\
+\xfb\x92\x52\x00\x43\xb9\x3e\x0c\xe5\xfa\x5e\xf7\x75\x4b\x6c\xb8\
+\xce\x44\xc4\x9c\x89\x70\xac\x3a\x00\x02\x4b\x2c\x04\x1a\x20\x50\
+\x1f\x81\x16\xe0\xfb\x05\xe4\xbc\x34\x3f\xd1\xd3\x68\xf9\x00\x1e\
+\x50\x95\xbb\x7c\xdf\xeb\xbc\xf7\xde\xaf\xb3\x3a\xa4\xb2\x28\x69\
+\x01\xb0\x6e\xdd\xe4\x7f\x51\xc5\x07\x46\xfb\x7a\xdf\xf7\xcb\xfa\
+\xe9\xdf\xb2\xec\xff\x2a\xdb\xcd\x42\xd2\xd8\xb8\xf0\xf3\xaa\x38\
+\xd7\x74\x8e\x5a\x15\xa8\x8f\x5c\x21\xc5\x4f\xf0\x34\x6e\x23\x7d\
+\xf6\xf5\xe7\xf9\xbc\xfc\x76\xd9\xb2\xd6\x3d\xa6\xf3\x50\xed\x29\
+\xd9\xa7\xc8\xf3\xcf\x6f\x73\xa6\x4f\x9f\xbc\x1e\xc0\xe9\xa3\xfd\
+\x99\x54\x6a\x00\x85\x42\x79\x3e\x35\x45\xb1\xf9\x4f\x53\xd3\x8f\
+\x27\xfb\x7e\xf6\x79\x00\x6f\x31\x9d\x85\x88\xc6\x64\x40\x04\xf7\
+\x00\xd6\xcf\x93\xc9\xe6\x27\x4c\x87\xa1\xda\x56\xb2\x19\x80\xe9\
+\xd3\x27\x7f\x11\x45\x0c\xfe\xf9\x7c\xae\x6c\x83\xbf\x88\xa8\xeb\
+\xc6\x1a\xcb\x72\xb3\x10\x05\x41\xb6\x19\x1c\xfc\x89\x22\x47\x04\
+\x7f\x02\xb0\xd8\xb2\xea\x7f\x93\x48\x5c\x5b\xbe\x69\x4e\xa2\x63\
+\x28\xc9\x0c\xc0\x45\x17\xdd\x5e\x57\x5f\x5f\x78\x1e\xd0\x53\x46\
+\xf3\x7a\xd5\x00\xfd\xfd\xfb\xca\x72\x5a\x99\x88\x60\xc2\x84\x09\
+\xb3\xbb\xbb\xdb\x6e\x2b\xf9\xcd\x42\xb4\x7f\xdb\xdf\x66\xb0\xe9\
+\x0f\x51\x54\xa4\x44\xf0\xab\x20\xb0\x7f\xdc\xd9\x39\x7b\x83\xe9\
+\x30\x44\x87\x2b\xc9\x0c\x40\x7d\x7d\xee\x6a\x40\x46\x35\xf8\x03\
+\x8a\x74\x3a\x5d\xa6\xc1\x1f\xa8\xab\x9b\x78\x63\x77\xf7\xbc\x48\
+\x0d\xfe\x00\xe0\x79\xc1\x1c\x11\x0e\xfe\x44\x11\xb0\x49\x55\x7f\
+\x9e\xcf\x7b\x8b\xef\xbb\xef\x3f\xf7\x99\x0e\x43\x74\x34\xa1\xcf\
+\x00\x5c\x7e\xf9\x82\x49\x99\x8c\xbc\x80\x51\x36\xa8\xc9\xe5\x86\
+\x91\xc9\x94\x7e\x41\xd5\xc8\xb4\x7f\xfd\x57\x7b\x7b\xe7\xff\xa8\
+\xe4\x37\x0b\x59\x53\xd3\xed\x7f\xe5\xfb\xf9\x17\x00\x44\xae\x61\
+\x11\x51\x8d\x08\x00\xfc\x4e\x44\x6f\x4f\x26\x5b\x97\xf3\xc0\x1d\
+\x8a\x82\xd0\x67\x00\x86\x86\xac\xaf\x01\x3a\xaa\xc1\x3f\x08\xca\
+\xb3\xea\x5f\x44\xfc\xfa\xfa\x58\xe3\x8a\x15\xf3\x97\x96\xfc\x66\
+\x25\xe0\xfb\xf9\x56\x70\xf0\x27\xaa\x44\x29\x40\x7e\x1e\x04\xd6\
+\x0f\x5f\x6b\xc9\x3b\xc7\x68\x20\xa2\xd1\x0a\x75\x06\x60\xe6\xcc\
+\xef\x9d\x58\x57\xe7\x6e\x06\x30\xaa\xd5\xf5\x03\x03\xfd\xf0\xfd\
+\xd2\xb6\x3b\xb5\x6d\x27\x65\xdb\xee\xff\xee\xed\x6d\x7b\xb6\xa4\
+\x37\x2a\x91\xa6\xa6\x5b\xa6\xf9\xbe\xf3\x12\xf8\xec\x9f\xa8\x92\
+\xec\x04\xf4\x27\xb6\x6d\xdf\x9e\x48\x34\xf3\xa0\x06\x8a\xa4\x50\
+\x67\x00\xea\xea\xdc\x56\x8c\x72\xf0\xcf\x66\x87\x4a\x3e\xf8\xbb\
+\x6e\x6c\x93\xe3\xd8\x67\x77\x77\xb7\x45\xb6\x6f\x76\x10\xb8\xd7\
+\x01\xca\xc1\x9f\xa8\x32\x6c\x12\xc1\x8f\xa7\x4c\x49\xdf\x71\xe7\
+\x9d\x6d\xc3\xa6\xc3\x10\x8d\x47\x68\x33\x00\xc5\x3c\xa7\xf6\xbc\
+\x02\x52\xa9\x01\x68\x31\x2d\x02\x8b\x20\x22\x88\xc5\xea\xee\xec\
+\xe9\xb9\x29\xd2\xed\x72\x9b\x9a\x16\xd5\xfb\x7e\xb0\x05\x3c\xf0\
+\x87\xc8\xb4\x3f\x88\xc8\xf7\x92\xc9\xe6\x6e\x3e\xdf\xa7\x6a\x11\
+\xda\x0c\x80\xe7\xe5\x6f\x10\x39\xfe\xe0\xaf\xaa\xc8\x64\x52\x25\
+\x1b\xfc\x6d\xdb\xf6\x5c\x77\xe2\xe7\x57\xae\xfc\xe6\x3d\x25\xb9\
+\x41\x19\xf9\xbe\xff\x59\x40\x38\xf8\x13\x99\xb3\x4a\xd5\xfa\x76\
+\x67\x67\xf3\xfe\xd3\x4c\x5b\xcc\xa6\x21\x0a\x51\x28\x05\x40\x53\
+\xd3\x2d\xa7\xf8\x3e\xae\x3a\xfe\x2b\x47\x06\x7f\xdf\xf7\xc3\xb8\
+\xed\x1b\x38\x4e\x6c\x4f\x2c\x66\xff\xfd\x8a\x15\xdf\x7c\xbe\x24\
+\x37\x28\x33\x11\xb9\xba\x44\x75\x12\x11\x1d\xdb\x2a\x40\x6e\xec\
+\xe8\x68\x79\xd4\x74\x10\xa2\x52\x09\xa5\x00\xf0\x7d\x77\x1e\xa0\
+\x75\xc7\x7b\x5d\x36\x9b\x45\x3e\x5f\x8a\x13\x2d\x05\xb1\x58\xdd\
+\xef\xa6\x4d\x5b\x7f\x61\x22\x91\x28\x4d\x75\x51\x66\x97\x5e\xba\
+\xe8\x5c\xd5\xe0\x43\xa6\x73\x10\xd5\x90\x40\x04\xc9\x20\x90\xef\
+\x74\x76\xb6\xfc\xd9\x74\x18\xa2\x52\x1b\x77\x01\xd0\xd8\xf8\xfd\
+\xd3\x55\xf5\x0b\xc7\x7b\x5d\xa1\x90\x47\x36\x3b\x34\xde\xdb\xbd\
+\x81\x65\x59\xbe\xeb\xba\x5f\xed\xe9\xb9\xe9\xc7\xa1\x5f\xdc\x20\
+\x91\xe0\x1a\xd3\x19\x88\x6a\xc8\x2a\x11\x99\x9b\x4c\xb6\x3c\x65\
+\x3a\x08\x51\xb9\x8c\xbb\x00\x50\xb5\xbe\x75\xbc\xeb\x04\x41\xb0\
+\xbf\xd9\x4f\xb8\xf3\xd9\xae\xeb\xbe\x12\x8b\x39\xe7\xdd\x77\x5f\
+\xdb\xe6\x50\x2f\x6c\xd8\x45\x17\xdd\x3e\x55\x24\xff\x69\xd3\x39\
+\x88\x6a\xc0\x7d\x40\x30\xaf\xa3\x63\xee\x93\xa6\x83\x10\x95\xdb\
+\xb8\x0a\x80\x4b\x2e\x59\x74\x16\x10\x1c\x77\xa0\xca\x64\x06\x11\
+\x04\xa1\xb6\xfa\xd5\x09\x13\xea\x7f\xbd\x72\x65\xdb\xe5\x61\x5e\
+\xb4\x52\x4c\x9c\x58\xb8\x4c\x15\xf5\xa6\x73\x10\x55\x2f\x79\x18\
+\xd0\x6f\x74\x74\xb4\xfe\xde\x74\x12\x22\x53\xc6\x55\x00\xd8\x76\
+\xf0\x1d\x00\xd6\xb1\x5e\x33\x34\x94\x46\xa1\x10\xde\x7e\x7f\xdb\
+\xb6\x53\xae\x1b\xbb\x78\xe5\xca\xb6\x35\xa1\x5d\xb4\xc2\xa8\xea\
+\xe7\x4c\x67\x20\xaa\x4e\xf2\xb0\x65\xf9\xff\xb9\x64\xc9\xdc\x87\
+\x4c\x27\x21\x32\x6d\xcc\x7d\x00\xe2\xf1\xf6\x73\x00\xac\x3d\xd6\
+\x35\xf2\xf9\x61\xa4\xd3\x61\xf5\xf9\x17\xb8\xae\xfb\x70\xa1\x60\
+\x7f\x72\xcd\x9a\xea\x6d\xc0\xd1\xd4\xb4\xe8\x6d\xbe\x1f\x6c\xc5\
+\x71\x0a\x2b\x22\x2a\x86\x6e\x50\xb5\xe6\x77\x76\x36\x2f\xe1\x3e\
+\x7e\xa2\x11\xe3\x99\x01\xb8\x05\xc7\x18\xfc\x3d\xaf\x80\x74\x3a\
+\x9c\x3e\xff\x22\x56\xc1\x71\x9c\x6b\xee\xbf\xff\xe6\x9f\x85\x72\
+\xc1\x0a\xe6\xfb\xc1\xbf\x82\x83\x3f\x51\x48\x64\xab\x88\xce\xb3\
+\xac\x53\xef\x4e\x24\x3e\xed\x73\x1f\x3f\xd1\x6b\xc6\x54\x00\x5c\
+\x76\xd9\xc2\x7f\x0c\x02\xfd\xc4\xd1\xbe\x1f\x04\x01\x52\xa9\x41\
+\x84\xb1\xe8\xcf\x75\x63\x1b\xea\xeb\x27\x7c\xfc\xde\x7b\x6f\xd8\
+\x39\xee\x8b\x45\x82\x34\x84\xbd\x58\x92\xa8\x06\xed\x55\xd5\xef\
+\x4f\x9b\x96\xfe\x21\x5b\xf6\x12\x1d\xd9\x18\x0a\x00\x15\xd5\x85\
+\xb7\x1e\xf5\xbb\xaa\x48\xa7\x07\xa1\x3a\xbe\x45\x7f\x96\x25\x81\
+\xe3\xd4\x7d\xb7\xb7\xf7\xa6\x1b\xc7\x75\xa1\x08\x69\x68\x58\x70\
+\x32\xa0\x1f\x31\x9d\x83\x28\xc2\x86\x55\x71\x9b\xe3\x78\xb7\x24\
+\x12\xd7\x0f\x98\x0e\x43\x54\xc9\x8a\x2e\x00\x1a\x1b\x17\xfe\xab\
+\x2a\x8e\xd2\xa0\x66\xa4\xd3\x9f\xe7\x8d\x6f\xd1\x9f\xeb\xba\xdb\
+\xea\xea\xf0\x89\xe5\xcb\x6f\xda\x34\xae\x0b\x45\x8c\x88\x5c\x0c\
+\xc0\x36\x9d\x83\x28\x82\x54\x04\x4b\x00\xfb\xfa\x8e\x8e\xd9\x55\
+\xb5\x2d\x98\xa8\x54\x8a\x2a\x00\x9a\x9a\xda\x62\xbe\x8f\x9b\x8f\
+\xf6\xfd\x6c\x76\x68\x5c\x9d\xfe\x44\x44\x27\x4c\x98\x70\x47\x77\
+\x77\xdb\xd5\x63\xbe\x48\xa4\xc9\x3f\x73\xfa\x9f\xa8\x58\xf2\xb0\
+\x48\xd0\x92\x4c\xce\x59\x6b\x3a\x09\x51\x94\x14\x55\x00\x78\xde\
+\xe4\x6b\x45\xf0\xae\x23\x7d\x2f\x97\x1b\x1e\x57\xa7\x3f\xd7\x75\
+\xb7\x89\x4c\xbc\xa0\xbb\xfb\x1b\x1b\xc7\x7c\x91\x08\x6b\x6a\xfa\
+\x1f\x3b\x08\xb6\x9e\xcf\xde\xff\x44\xa3\x25\x5b\x55\x71\x63\x67\
+\x67\xf3\x5d\x5c\xd9\x4f\x54\xbc\x51\x17\x00\x4d\x4d\xb7\x4c\xf3\
+\x7d\xdc\x70\xa4\xef\x15\x0a\xf9\xfd\x9d\xfe\x8a\x27\x22\xea\xba\
+\x13\x16\xf7\xf6\xb6\x8d\xe2\x30\xa1\xea\x55\x28\x6c\xfb\x90\x65\
+\xe1\x44\xd3\x39\x88\x22\x20\x23\x82\x6f\x0f\x0d\xb9\x3f\xe8\xee\
+\x9e\x95\xe3\xca\x7e\xa2\xb1\x19\x75\x01\xe0\x79\xce\xf5\x22\x98\
+\x71\xf8\xd7\x7d\xdf\x43\x3a\x3d\x38\xb6\x9b\x3b\xce\x76\xcb\x72\
+\x2f\xec\xed\x6d\x7b\x76\x4c\x17\xa8\x22\x96\x15\x7c\xd2\x74\x06\
+\xa2\x4a\x27\x82\xe5\xaa\xb8\x2e\x99\x6c\x7d\xc9\x74\x16\xa2\xa8\
+\x1b\x55\x01\x30\xd2\x9c\x46\x67\x1d\xfe\x7c\xda\xf7\x7d\xa4\x52\
+\x03\xd0\x22\xe7\xad\x45\xac\x20\x16\xab\xbb\xad\xa7\xa7\x8d\xa5\
+\xfb\x6b\xce\x33\x1d\x80\xa8\x82\x3d\x6b\x59\xfa\x95\x25\x4b\xe6\
+\xac\x31\x1d\x84\xa8\x5a\x8c\xaa\xe1\x8c\xef\x07\x37\x03\x3a\xf1\
+\xd0\xaf\x8d\x6c\xf7\x1b\x28\xba\xc7\xbf\xeb\xba\xdb\x26\x4d\xb2\
+\xcf\xe0\xe0\x7f\x28\x15\x11\x9c\x6b\x3a\x05\x51\x05\x1a\x50\xd5\
+\xeb\x6d\x3b\xfd\x21\x0e\xfe\x44\xe1\x3a\x6e\x2b\xe0\x86\x86\x1f\
+\x9c\x29\xe2\x3f\x83\x43\x66\x0b\x54\x15\xa9\xd4\x40\x51\xdb\xfd\
+\x2c\xcb\xf6\x5c\xb7\xee\x9b\x3d\x3d\xf3\x8f\xda\x43\xa0\x56\x35\
+\x36\xb6\x9f\xa1\x8a\x0d\xa6\x73\x10\x55\x10\x05\x70\xb7\xe7\x39\
+\x73\xee\xbd\xf7\x6b\x35\xd2\x04\x8c\xa8\xbc\x8e\xfb\x08\x40\xc4\
+\x5f\x70\xf8\xeb\xd2\xe9\xc1\xa2\x06\x7f\xd7\xad\xfb\x73\x7d\xfd\
+\xf4\x7f\xe2\xff\xc8\x47\xf5\x61\xd3\x01\x88\x2a\xc8\x53\x96\x25\
+\xd7\x2d\x59\xd2\xf2\x88\xe9\x20\x44\xd5\xec\x98\x05\x40\x43\xc3\
+\xa2\x8f\x01\xc1\xcc\xd7\xbe\xa2\x48\xa7\x53\x28\x14\xf2\xa3\xba\
+\xb8\x65\xd9\x59\xd7\xad\xbb\xb6\xa7\x67\xfe\x7f\x8f\x2b\x65\x95\
+\x0b\x02\xfc\x2f\x19\xf3\xb1\x4c\x44\x55\x63\x8f\x08\x6e\x38\xeb\
+\xac\xf4\xcf\xda\xda\xda\x42\x3d\x3f\x9c\x88\xde\xe8\x18\x05\x80\
+\x8a\xc8\xc2\x5b\x0e\xf9\x33\x32\x99\xf4\xa8\x1a\xfd\x88\x08\x5c\
+\xd7\x5d\x95\xcf\xdb\x9f\xea\xe9\x99\xcf\x3e\xdc\xc7\xf7\x5e\xd3\
+\x01\x88\x0c\x0a\x00\xfc\xda\xb6\x63\x2d\x89\xc4\xac\xdd\xc9\xa4\
+\xe9\x38\x44\xb5\xe1\xa8\x05\x40\x43\x43\xfb\xbf\x00\x72\xb0\x2f\
+\xfd\xd0\x50\x06\xb9\xdc\xf1\xc7\x72\xc7\x71\x76\xbb\x6e\x5d\x43\
+\x77\xf7\xbc\x87\x43\xca\x58\xf5\x44\xf0\x6e\xd3\x19\x88\x0c\x79\
+\x4c\x44\xae\x4a\x26\x5b\x9e\x32\x1d\x84\xa8\xd6\x1c\x71\xe2\xf9\
+\xca\x2b\xef\x70\xf7\xec\x49\xad\x07\xf0\x37\xc0\x48\x8b\xdf\x6c\
+\x36\x73\xcc\x0b\x59\x96\xf8\xae\x5b\xf7\xc3\x9e\x9e\x9b\xb8\xba\
+\xbf\x08\x33\x67\x7e\xef\xc4\xba\x3a\x77\xaf\xe9\x1c\x44\x65\x96\
+\x51\xd5\x9b\x1d\xe7\xd4\xf6\x91\x63\x7a\x89\xa8\xdc\x8e\x38\x03\
+\xb0\x7b\x77\xea\x3a\x91\xd1\x0d\xfe\x22\x02\xc7\x71\x1f\x17\xb1\
+\xff\x4f\x4f\x4f\xdb\xae\x12\xe5\xac\x5a\x75\x75\xb1\xbf\x63\xff\
+\x7f\xaa\x31\x5d\xb6\x6d\x5d\x97\x48\x34\xbf\x62\x3a\x08\x51\x2d\
+\x7b\x43\x01\x70\xf1\xc5\xb7\xbd\x49\xc4\x9b\x0f\x00\xd9\x6c\xe6\
+\x98\xfd\xfd\x1d\xc7\x19\x88\xc5\x62\x5f\x58\xb1\x62\xfe\xd2\x12\
+\x66\xac\x6a\xaa\xc1\x69\xc2\x15\x80\x54\x1b\xb6\x03\x98\xd5\xd1\
+\xd1\xba\xc4\x74\x10\x22\x3a\x42\x01\xe0\x38\xde\x42\x00\xd3\x8e\
+\x35\xf8\x8b\x58\x7e\x2c\x56\xf7\xd3\x9e\x9e\xf9\xd7\xf0\x10\x8e\
+\x71\x3b\xd5\x74\x00\xa2\x12\x0b\x00\xfc\x2c\x9b\x8d\xcd\xe9\xee\
+\x9e\x35\xb6\xbe\xe1\x44\x14\xba\xd7\x15\x00\x0d\x0d\xed\xff\x00\
+\xe0\xb3\x47\x1b\xfc\xf7\xaf\xee\x5f\xeb\x38\x53\x2e\x5d\xb1\x62\
+\xee\x0e\xa0\xad\x4c\x31\xab\x97\x88\x9c\x62\x3a\x03\x51\x09\x3d\
+\x03\xc8\x7f\x74\x74\xb4\x3c\x6a\x3a\x08\x11\xbd\xde\xc1\x02\xe0\
+\xfc\xf3\xdb\x1c\x11\xfc\xdf\x6c\x36\x23\x47\x1a\xfc\x1d\xc7\xdd\
+\xee\xba\xb1\xcf\x74\x77\xcf\x7b\xb0\xac\x09\xab\xdf\x5b\x4d\x07\
+\x20\x2a\x81\x2c\xa0\xdf\xb7\xed\xcc\x77\x13\x89\xb6\xd1\x35\x0e\
+\x21\xa2\xb2\x3a\x58\x00\x4c\x9f\x3e\xf9\xab\xd9\xec\xd0\xfb\x0f\
+\x1f\xfc\x1d\xc7\x19\xb4\xac\xba\xd9\xbd\xbd\xf3\x7e\x51\xf6\x74\
+\xb5\xe1\x24\xd3\x01\x88\x42\xf6\x80\xaa\x5c\xd5\xd9\xd9\xfa\xbc\
+\xe9\x20\x44\x74\x74\x0e\x00\x34\x34\xdc\x7a\x66\x26\x93\xbe\x25\
+\x97\xcb\x1e\xfc\x86\x65\x59\x9e\xeb\x4e\xb8\xa3\xa7\x47\x67\x01\
+\xf3\xd8\x95\xab\x64\x74\xc6\x28\x8e\x64\x20\x8a\x82\x9d\xaa\xfa\
+\xb5\xce\xce\x39\xbf\x35\x1d\x84\x88\x8e\xcf\xb9\xf8\xe2\xb9\x53\
+\x32\x99\xcc\x1f\xf2\xf9\x9c\x03\x00\x96\x65\xf9\x8e\x53\xb7\x04\
+\x98\xf4\x6f\x3d\x3d\x73\x8e\xbd\xf9\x9f\xc2\xc0\x19\x00\xaa\x06\
+\x77\xd9\xb6\xf5\xb5\x44\xa2\x99\x3d\x2d\x88\x22\xc2\xc9\xe5\x26\
+\xdd\x9f\xcf\x0f\x4d\xb7\x6d\x3b\xef\xba\xb1\x84\x08\xae\xe9\xee\
+\x6e\xe3\x4a\xdd\xb2\x91\x29\xa6\x13\x10\x8d\xc3\x0e\x11\x5c\x9d\
+\x4c\xb6\x76\x99\x0e\x42\x44\xc5\x71\x1c\xc7\x5e\x0d\x4c\xbe\xa3\
+\xa7\xe7\xc6\x3b\xc1\x8e\x34\x26\xc4\x4c\x07\x20\x1a\x0b\x11\x24\
+\x2c\xcb\xba\x8a\x9f\xfa\x89\xa2\x89\x0f\x9f\x0d\xba\xe8\xa2\xdb\
+\xeb\xea\xeb\xf3\x3c\x2c\x89\xa2\xe6\x55\x11\xbd\x2a\x99\x9c\xb3\
+\xcc\x74\x10\x22\x1a\x3b\xcb\x74\x80\x1a\x57\x67\x3a\x00\x51\x11\
+\x54\x04\x3f\xf1\x3c\xff\x0c\x0e\xfe\x44\xd1\x77\x8c\xe3\x80\xa9\
+\xd4\x5c\x37\xab\x80\x6d\x3a\x06\xd1\x68\x6c\xb1\x2c\xf9\xf7\x25\
+\x4b\x5a\x56\x9b\x0e\x42\x44\xe1\xe0\x0c\x80\x41\xaa\x59\x9e\x82\
+\x46\x95\x4e\x01\x2c\xb6\xed\xfa\xf7\x71\xf0\x27\xaa\x2e\x9c\x01\
+\x30\xc8\xf3\xa6\xfb\xae\xcb\x26\x69\x54\xb1\x36\x03\xf2\xe5\x8e\
+\x8e\x96\x07\x4c\x07\x21\xa2\xf0\x71\x06\xc0\xa0\xc9\x93\xdf\xec\
+\x81\x3b\x2f\xa8\xf2\xf8\x00\x16\xda\xb6\xf5\x5e\x0e\xfe\x44\xd5\
+\x8b\xbb\x00\x0c\x8b\xc7\xdb\xd3\x00\x26\x99\xce\x41\xb4\xdf\x16\
+\x55\xeb\x8a\xce\xce\x66\x9e\xf9\x41\x54\xe5\x38\x03\x60\xde\x80\
+\xe9\x00\x44\x38\xe4\x59\x3f\x07\x7f\xa2\xda\xc0\x35\x00\xe6\x0d\
+\x82\x27\x02\x92\x51\xb2\xd5\xb2\xf0\x25\x2e\xf2\x23\xaa\x2d\x2c\
+\x00\xcc\xdb\x63\x3a\x00\xd5\x2e\x55\xfc\x62\x78\xd8\x9d\xdd\xdd\
+\x3d\x8b\xed\xbf\x89\x6a\x0c\x0b\x00\xc3\x44\xb0\x5d\xb9\x0c\x90\
+\xca\x6f\xa7\xaa\xfe\x47\x67\xe7\x9c\xa5\xa6\x83\x10\x91\x19\x2c\
+\x00\x0c\x0b\x02\xbc\x2a\x5c\x8a\x49\x65\x24\x82\x44\x3e\x8f\x6b\
+\x96\x2d\x9b\xc3\xd9\x27\xa2\x1a\xc6\x02\xc0\x30\x11\xbc\x6a\x3a\
+\x03\xd5\x8c\x3d\xaa\x72\x4d\x47\x47\x4b\xc2\x74\x10\x22\x32\x8f\
+\x05\x80\x61\xaa\xb2\x45\x84\xcf\x00\xa8\xb4\x44\xd0\x5d\x28\xf8\
+\x5f\xbe\xf7\xde\xaf\xb3\xe0\x24\x22\x00\x2c\x00\x2a\xc1\xf3\xa6\
+\x03\x50\x55\x1b\x10\xc1\x57\x93\xc9\xd6\x5f\x9a\x0e\x42\x44\x95\
+\x85\x7d\x00\x0c\xf3\xbc\xd4\x26\xb0\x1b\x20\x95\xc6\x23\x41\x10\
+\x7c\x88\x83\x3f\x11\x1d\x09\x0b\x00\xc3\x96\x2d\x6b\x1b\x02\xb0\
+\xd5\x74\x0e\xaa\x2a\xc3\x00\x5a\xdf\xf7\xbe\xf4\x47\xbb\xba\xe6\
+\xbe\x60\x3a\x0c\x11\x55\x26\x3e\x02\xa8\x00\x22\xf2\xb4\xaa\x9e\
+\x6a\x3a\x07\x55\x85\x67\x83\x20\xb8\xbc\xab\x6b\xee\xd3\x1d\x1d\
+\xa6\xa3\x10\x51\x25\xe3\x0c\x40\x05\x50\xc5\x53\xa6\x33\x50\xe4\
+\xa9\x88\xdc\x9e\xcd\xc6\xce\xee\xea\x9a\xfb\xb4\xe9\x30\x44\x54\
+\xf9\x38\x03\x50\x19\x58\x00\xd0\x78\x6c\x51\xc5\xe7\x3b\x3a\x5a\
+\xfe\x60\x3a\x08\x11\x45\x07\x67\x00\x2a\x80\xe7\xd9\x6b\x4d\x67\
+\xa0\x68\x12\x41\x22\x08\xec\x0f\x76\x76\xb6\x72\xf0\x27\xa2\xa2\
+\xb0\x07\x5d\x85\x88\xc7\xdb\x9f\x07\x70\xba\xe9\x1c\x14\x15\xba\
+\x5b\x44\xae\x4c\x26\x5b\xbb\x4c\x27\x21\xa2\x68\xe2\x0c\x40\x85\
+\x50\xc5\x43\xa6\x33\x50\x54\xe8\x4a\xcf\x0b\x3e\xc0\xc1\x9f\x88\
+\xc6\x83\x6b\x00\x2a\x84\x08\xd6\x00\xf8\x92\xe9\x1c\x54\xd1\xd2\
+\x00\x66\x77\x74\xcc\xf9\x99\xe9\x20\x44\x14\x7d\x2c\x00\x2a\x84\
+\x6d\x5b\xf7\xf9\x7e\xe0\x81\x7f\x27\x74\x64\x6b\x45\x82\xcb\x93\
+\xc9\xb9\x9b\x4c\x07\x21\xa2\xea\xc0\x47\x00\x15\x22\x91\x68\xde\
+\x0b\xe0\x11\xd3\x39\xa8\xe2\x78\x22\x72\xeb\x49\x27\x4d\xf9\x28\
+\x07\x7f\x22\x0a\x13\x3f\x6d\x56\x10\x55\x59\x26\xa2\xe7\x99\xce\
+\x41\x15\x63\xa3\x88\x75\x79\x32\xd9\xfc\x84\xe9\x20\x44\x54\x7d\
+\x38\x03\x50\x41\x1c\x47\xb8\xa8\x8b\x80\x91\xb3\x21\x16\x4f\x9a\
+\xa4\x67\x73\xf0\x27\xa2\x52\xe1\x36\xc0\x0a\x13\x8f\xb7\x6f\x00\
+\x70\x86\xe9\x1c\x64\xcc\x4e\x55\xf9\x72\x67\x67\xcb\x72\xd3\x41\
+\x88\xa8\xba\x71\x06\xa0\xf2\xdc\x6b\x3a\x00\x99\xa2\xc9\x42\x01\
+\xef\xe5\xe0\x4f\x44\xe5\xc0\x35\x00\x15\x46\x44\x7f\xad\x2a\x73\
+\x4d\xe7\xa0\xf2\x51\xc5\xa0\x65\x61\x4e\x32\x39\x67\xb1\xe9\x2c\
+\x44\x54\x3b\xf8\x08\xa0\x02\xc5\xe3\xed\x6b\x01\x9c\x6b\x3a\x07\
+\x95\xc5\x1f\xf7\x9f\xde\xc7\x63\x7b\x89\xf0\xd9\xf1\x9b\x00\x00\
+\x05\x8e\x49\x44\x41\x54\xa8\xac\xf8\x08\xa0\x02\x89\xc8\x1d\xa6\
+\x33\x50\xc9\x15\x00\xbd\xc9\xb6\x4f\xf9\x28\x07\x7f\x22\x32\x81\
+\x8f\x00\x2a\x90\x65\xc9\x3d\x41\xa0\xed\xaa\x38\xd1\x74\x16\x0a\
+\x9f\x2a\xd6\x5b\x96\x7c\x2e\x99\x6c\xe5\x29\x90\x44\x64\x0c\x67\
+\x00\x2a\x50\x22\xd1\x9c\x05\xf0\x1b\xd3\x39\x28\x74\x0a\x60\xb1\
+\xe7\xa5\xcf\x49\x26\x5b\x38\xf8\x13\x91\x51\x9c\x01\xa8\x50\x9e\
+\x67\xdd\x61\xdb\xc1\xb5\xa6\x73\x50\x68\x76\x04\x01\xbe\xd4\xd5\
+\xd5\xda\x6d\x3a\x08\x11\x11\xc0\x19\x80\x8a\xb5\x74\x69\xf3\x3a\
+\x55\xac\x31\x9d\x83\xc6\x4f\x15\xf7\x04\x81\x7d\x26\x07\x7f\x22\
+\xaa\x24\x9c\x01\xa8\x6c\x37\x02\x3c\x26\x38\xc2\x06\x00\x7c\xa5\
+\xb3\xb3\xf5\x2e\xd3\x41\x88\x88\x0e\xc7\x6d\x80\x15\x2e\x1e\x6f\
+\xff\x1d\x80\x8f\x9b\xce\x41\xc5\x51\xc5\xea\x20\x90\x2b\x96\x2e\
+\x6d\x79\xd9\x74\x16\x22\xa2\x23\xe1\x23\x80\x8a\x17\xdc\x68\x3a\
+\x01\x15\x65\x58\x55\xaf\x7f\xff\xfb\xd3\x17\x72\xf0\x27\xa2\x4a\
+\xc6\x19\x80\x08\x88\xc7\xdb\xef\x07\xf0\x49\xd3\x39\xe8\xd8\x44\
+\xf0\x34\x60\x7d\x2e\x99\x6c\x7e\xce\x74\x16\x22\xa2\xe3\xe1\x0c\
+\x40\x04\xa8\xea\x3c\xd3\x19\xe8\x98\x3c\x11\xb9\xd5\xb2\xd2\x1f\
+\xe6\xe0\x4f\x44\x51\xc1\x19\x80\x88\x88\xc7\xdb\x97\x02\xb8\xd8\
+\x74\x0e\x7a\x83\x8d\x41\x60\x7d\xa1\xab\xab\xf9\x31\xd3\x41\x88\
+\x88\x8a\xc1\x19\x80\x88\xb0\x6d\xef\x2b\x00\xd2\xa6\x73\xd0\x41\
+\x0a\x60\xf1\xa4\x49\x7a\x36\x07\x7f\x22\x8a\x22\xce\x00\x44\x48\
+\x63\xe3\x82\x39\xaa\xf2\x7d\xd3\x39\x08\x2f\x01\x72\x45\x47\x47\
+\xcb\x03\xa6\x83\x10\x11\x8d\x15\x67\x00\x22\xa4\xaf\x2f\xf3\x83\
+\x91\x85\x66\x64\xd0\x5d\x9e\xe7\x9f\xc5\xc1\x9f\x88\xa2\x8e\x33\
+\x00\x11\x73\xe9\xa5\x8b\xce\xb5\xac\xe0\x8f\x60\xf1\x56\x6e\x3b\
+\x01\xb9\xb2\xa3\xa3\xe5\x5e\xd3\x41\x88\x88\xc2\x60\x9b\x0e\x40\
+\xc5\xd9\xb8\xb1\xe7\x95\x33\xcf\xbc\xe0\xad\x80\x9c\x6d\x3a\x4b\
+\xad\x50\xc5\x3d\x8e\x63\xcd\x4c\x26\x5b\x38\xfb\x42\x44\x55\x83\
+\xad\x80\x23\xc8\xb6\x27\xb6\xfa\x7e\xf6\x63\x00\xce\x30\x9d\xa5\
+\xca\xed\x51\x95\x6b\x3a\x3b\x5b\x12\xa6\x83\x10\x11\x85\x8d\xd3\
+\xc8\x11\x94\x48\x5c\x9b\x56\xd5\x26\x40\x86\x4c\x67\xa9\x56\x22\
+\x58\xee\x79\xfe\xfb\x39\xf8\x13\x51\xb5\xe2\x1a\x80\x08\x6b\x68\
+\x58\xf0\xef\x22\xb2\xd8\x74\x8e\x2a\xb3\x13\xc0\x75\x1d\x1d\xad\
+\x4b\x4c\x07\x21\x22\x2a\x25\xae\x01\x88\xb0\x8d\x1b\xef\x7f\xf2\
+\xcc\x33\x2f\x7c\x17\x80\xf7\x9b\xce\x52\x0d\x44\x90\x28\x14\x30\
+\x73\xe9\xd2\xd6\x27\x4c\x67\x21\x22\x2a\x35\xae\x01\x88\x38\xdb\
+\xae\xbf\xc6\xf3\xb2\xe7\x8a\xe0\xef\x4c\x67\x89\xb0\x57\x54\xe5\
+\xaa\x8e\x8e\x96\xe5\xa6\x83\x10\x11\x95\x0b\xd7\x00\x44\xdc\xc8\
+\x7a\x80\x60\x26\x46\xa6\xae\xa9\x48\x22\x48\xd8\xb6\xf5\xbe\xce\
+\x4e\x0e\xfe\x44\x54\x5b\xb8\x06\xa0\x4a\x34\x36\x2e\x3a\x5b\x35\
+\x78\x00\xc0\x64\xd3\x59\x22\xe2\x55\x11\xbd\x2a\x99\x9c\xb3\xcc\
+\x74\x10\x22\x22\x13\x38\x03\x50\x25\x92\xc9\xe6\x27\x54\xf5\x12\
+\x00\x39\xd3\x59\x2a\x9c\x02\x58\xec\x79\xfe\x19\x1c\xfc\x89\xa8\
+\x96\x71\x06\xa0\xca\x34\x36\x2e\xfc\x9c\xaa\xfe\x0a\xfc\xbb\x3d\
+\x02\xdd\x00\xc8\x55\x1d\x1d\xad\xbf\x37\x9d\x84\x88\xc8\x34\xee\
+\x02\xa8\x32\x1b\x36\xf4\x3e\xf3\xee\x77\x5f\xd8\x0f\xe0\x9f\xc0\
+\x22\xe0\x80\x2c\x80\x6f\xd9\x76\xe6\xf2\x64\xf2\x1b\x9b\x4d\x87\
+\x21\x22\xaa\x04\x1c\x20\xaa\x54\x3c\xde\x7e\x39\x80\x5f\xa0\xc6\
+\x77\x7a\xa8\x62\x8d\x65\xe1\xea\x64\xb2\x75\xa3\xe9\x2c\x44\x44\
+\x95\x84\x05\x40\x15\x6b\x6c\x5c\xf0\x29\x55\xf9\x7f\x00\xea\x4d\
+\x67\x31\x60\x87\xaa\x7c\xbd\xb3\xb3\xe5\x57\xa6\x83\x10\x11\x55\
+\x22\x16\x00\x55\xae\xa1\x61\xd1\xc7\x44\x82\xa5\x00\xa6\x99\xce\
+\x52\x26\x0a\xe0\x6e\xd5\xfc\xec\xce\xce\x6f\xf4\x99\x0e\x43\x44\
+\x54\xa9\x58\x00\xd4\x80\x78\xfc\xfb\x1f\x04\xac\xa5\x00\xde\x6e\
+\x3a\x4b\x29\x89\xe0\x69\x40\xaf\x4a\x26\xe7\xac\x35\x9d\x85\x88\
+\xa8\xd2\xb1\x00\xa8\x11\x9f\xfa\x54\xfb\x49\xb1\x18\x7e\xa5\x8a\
+\x8b\x4c\x67\x29\x81\xb4\x88\xcc\xef\xeb\x4b\xdd\xbe\x66\x4d\x9b\
+\x67\x3a\x0c\x11\x51\x14\xb0\x00\xa8\x29\x2a\x8d\x8d\x0b\x67\xa9\
+\x62\x01\x00\xd7\x74\x9a\x10\xa8\x08\x96\x58\x96\xd7\x9a\x48\x5c\
+\xbf\xd5\x74\x18\x22\xa2\x28\x61\x01\x50\x83\xe2\xf1\xf6\xf3\x00\
+\xdc\x03\xe0\xad\xa6\xb3\x8c\xc3\x5a\x55\x9d\xdd\xd9\x39\xe7\x8f\
+\xa6\x83\x10\x11\x45\x11\x0b\x80\x1a\xd5\xd0\xf0\xdd\x19\x22\xee\
+\x22\x40\x3e\x6f\x3a\x4b\x91\xb6\xec\x5f\xdd\x9f\x30\x1d\x84\x88\
+\x28\xca\x58\x00\xd4\xb8\x86\x86\xf6\x0b\x00\xfc\x28\x02\xa7\x09\
+\xa6\x44\xf0\xdd\x29\x53\xd2\xb7\xdd\x79\x67\xdb\xb0\xe9\x30\x44\
+\x44\x51\xc7\x02\x80\x70\xe5\x95\x77\xb8\x7d\x7d\xa9\x2b\x54\x71\
+\x33\x80\x93\x4d\xe7\x39\x4c\x00\xe0\xd7\xb6\x1d\xcc\x4d\x24\xe6\
+\xee\x30\x1d\x86\x88\xa8\x5a\xb0\x00\xa0\x83\x2e\xba\xe8\xf6\xa9\
+\xf5\xf5\xf9\x59\x00\xbe\x06\x60\x86\xe9\x3c\x00\x7e\x17\x04\x41\
+\x4b\x57\xd7\xdc\xa7\x4d\x07\x21\x22\xaa\x36\x2c\x00\xe8\x0d\x2e\
+\xbe\xf8\xd6\x29\xb6\x6d\x5d\x01\xc8\x35\x26\x1e\x0d\xa8\x4a\xaf\
+\x6d\xfb\xdf\x5e\xb2\x64\xee\x43\xe5\xbe\x37\x11\x51\xad\x60\x01\
+\x40\xc7\xa0\x72\xd9\x65\x8b\x3e\x11\x04\xfa\x39\x00\x0d\x28\x6d\
+\x37\xc1\x7e\x00\x77\xf9\xbe\xf5\xd3\xa5\x4b\x9b\xd7\x95\xf0\x3e\
+\x44\x44\x04\x16\x00\x34\x4a\x5f\xfc\x62\xdb\x84\x54\x6a\xca\x27\
+\x46\x1a\x09\xe9\x85\x00\xfe\x36\x84\xcb\x6e\x13\x91\x6e\xd5\x60\
+\xe9\xd4\xa9\x99\xd5\x5c\xdc\x47\x44\x54\x3e\x2c\x00\x68\x4c\x46\
+\x3a\x0b\xca\xb9\xaa\xfa\x01\x00\xa7\x03\xf8\x1b\x00\x6f\x06\x30\
+\x7d\xff\x3f\xfb\xc9\x10\xa0\x7d\x80\xec\x06\x74\x33\x20\x9b\x80\
+\xe0\x59\x40\x1e\xee\xe8\x68\x7d\xc9\x48\x78\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\
+\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\x22\xa2\x1a\xf2\xff\x01\
+\xb0\x4e\x40\xbe\x35\x7f\xa8\x19\x00\x00\x00\x00\x49\x45\x4e\x44\
+\xae\x42\x60\x82\
+\x00\x00\x02\x16\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x31\x31\x2e\x36\x37\x20\x32\x31\x31\x2e\x36\x37\x22\x20\x78\x6d\
+\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\
+\x3e\x0a\x20\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x30\x35\
+\x2e\x38\x33\x20\x30\x63\x2d\x35\x38\x2e\x34\x35\x2d\x33\x2e\x33\
+\x31\x33\x37\x65\x2d\x36\x20\x2d\x31\x30\x35\x2e\x38\x33\x20\x34\
+\x37\x2e\x33\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x20\x31\x30\x35\
+\x2e\x38\x33\x2d\x34\x2e\x32\x39\x33\x36\x65\x2d\x31\x34\x20\x32\
+\x35\x2e\x30\x39\x36\x20\x38\x2e\x37\x35\x33\x32\x20\x34\x38\x2e\
+\x31\x33\x37\x20\x32\x33\x2e\x33\x34\x39\x20\x36\x36\x2e\x32\x37\
+\x39\x20\x33\x33\x2e\x39\x31\x2d\x33\x34\x2e\x35\x39\x31\x20\x31\
+\x31\x34\x2e\x33\x34\x2d\x31\x31\x34\x2e\x36\x39\x20\x31\x34\x38\
+\x2e\x37\x37\x2d\x31\x34\x38\x2e\x37\x35\x2d\x31\x38\x2e\x31\x34\
+\x33\x2d\x31\x34\x2e\x36\x30\x31\x2d\x34\x31\x2e\x31\x38\x39\x2d\
+\x32\x33\x2e\x33\x35\x38\x2d\x36\x36\x2e\x32\x39\x31\x2d\x32\x33\
+\x2e\x33\x35\x38\x7a\x6d\x38\x32\x2e\x36\x37\x36\x20\x33\x39\x2e\
+\x37\x39\x38\x2d\x31\x34\x38\x2e\x37\x31\x20\x31\x34\x38\x2e\x37\
+\x31\x63\x31\x38\x2e\x31\x30\x34\x20\x31\x34\x2e\x34\x37\x39\x20\
+\x34\x31\x2e\x30\x35\x31\x20\x32\x33\x2e\x31\x35\x38\x20\x36\x36\
+\x2e\x30\x33\x36\x20\x32\x33\x2e\x31\x35\x38\x20\x35\x38\x2e\x34\
+\x35\x20\x30\x20\x31\x30\x35\x2e\x38\x33\x2d\x34\x37\x2e\x33\x38\
+\x33\x20\x31\x30\x35\x2e\x38\x33\x2d\x31\x30\x35\x2e\x38\x33\x20\
+\x30\x2d\x32\x34\x2e\x39\x38\x35\x2d\x38\x2e\x36\x37\x38\x33\x2d\
+\x34\x37\x2e\x39\x33\x32\x2d\x32\x33\x2e\x31\x35\x38\x2d\x36\x36\
+\x2e\x30\x33\x36\x7a\x22\x20\x66\x69\x6c\x6c\x3d\x22\x23\x62\x66\
+\x62\x66\x62\x66\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\
+\x74\x68\x3d\x22\x2e\x33\x31\x34\x37\x39\x22\x2f\x3e\x0a\x3c\x2f\
+\x73\x76\x67\x3e\x0a\
+\x00\x00\x03\x7c\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\
+\x31\x32\x20\x35\x31\x32\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\
+\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\
+\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\x0a\x20\x3c\x70\x61\
+\x74\x68\x20\x64\x3d\x22\x6d\x31\x37\x35\x2e\x32\x31\x20\x34\x34\
+\x37\x2e\x38\x36\x20\x33\x32\x2e\x37\x32\x36\x20\x34\x2e\x38\x36\
+\x32\x32\x71\x32\x2e\x30\x35\x37\x31\x20\x31\x35\x2e\x31\x34\x38\
+\x20\x31\x31\x2e\x34\x30\x37\x20\x32\x32\x2e\x30\x36\x37\x20\x31\
+\x32\x2e\x35\x32\x39\x20\x39\x2e\x33\x35\x30\x33\x20\x33\x34\x2e\
+\x32\x32\x32\x20\x39\x2e\x33\x35\x30\x33\x20\x32\x33\x2e\x33\x37\
+\x36\x20\x30\x20\x33\x36\x2e\x30\x39\x32\x2d\x39\x2e\x33\x35\x30\
+\x33\x74\x31\x37\x2e\x32\x30\x35\x2d\x32\x36\x2e\x31\x38\x31\x71\
+\x32\x2e\x36\x31\x38\x31\x2d\x31\x30\x2e\x32\x38\x35\x20\x32\x2e\
+\x34\x33\x31\x31\x2d\x34\x33\x2e\x31\x39\x38\x2d\x32\x32\x2e\x30\
+\x36\x37\x20\x32\x35\x2e\x39\x39\x34\x2d\x35\x34\x2e\x39\x38\x20\
+\x32\x35\x2e\x39\x39\x34\x2d\x34\x30\x2e\x39\x35\x34\x20\x30\x2d\
+\x36\x33\x2e\x33\x39\x35\x2d\x32\x39\x2e\x35\x34\x37\x2d\x32\x32\
+\x2e\x34\x34\x31\x2d\x32\x39\x2e\x35\x34\x37\x2d\x32\x32\x2e\x34\
+\x34\x31\x2d\x37\x30\x2e\x38\x37\x35\x20\x30\x2d\x32\x38\x2e\x34\
+\x32\x35\x20\x31\x30\x2e\x32\x38\x35\x2d\x35\x32\x2e\x33\x36\x32\
+\x20\x31\x30\x2e\x32\x38\x35\x2d\x32\x34\x2e\x31\x32\x34\x20\x32\
+\x39\x2e\x37\x33\x34\x2d\x33\x37\x2e\x32\x31\x34\x20\x31\x39\x2e\
+\x36\x33\x36\x2d\x31\x33\x2e\x30\x39\x20\x34\x36\x2e\x30\x30\x34\
+\x2d\x31\x33\x2e\x30\x39\x20\x33\x35\x2e\x31\x35\x37\x20\x30\x20\
+\x35\x37\x2e\x39\x37\x32\x20\x32\x38\x2e\x34\x32\x35\x76\x2d\x32\
+\x33\x2e\x39\x33\x37\x68\x33\x31\x2e\x30\x34\x33\x76\x31\x37\x31\
+\x2e\x36\x37\x71\x30\x20\x34\x36\x2e\x33\x37\x38\x2d\x39\x2e\x35\
+\x33\x37\x33\x20\x36\x35\x2e\x36\x33\x39\x2d\x39\x2e\x33\x35\x30\
+\x33\x20\x31\x39\x2e\x34\x34\x39\x2d\x32\x39\x2e\x39\x32\x31\x20\
+\x33\x30\x2e\x36\x36\x39\x2d\x32\x30\x2e\x33\x38\x34\x20\x31\x31\
+\x2e\x32\x32\x2d\x35\x30\x2e\x33\x30\x35\x20\x31\x31\x2e\x32\x32\
+\x2d\x33\x35\x2e\x35\x33\x31\x20\x30\x2d\x35\x37\x2e\x34\x31\x31\
+\x2d\x31\x36\x2e\x30\x38\x33\x2d\x32\x31\x2e\x38\x38\x2d\x31\x35\
+\x2e\x38\x39\x36\x2d\x32\x31\x2e\x31\x33\x32\x2d\x34\x38\x2e\x30\
+\x36\x31\x7a\x6d\x32\x37\x2e\x38\x36\x34\x2d\x31\x31\x39\x2e\x33\
+\x31\x71\x30\x20\x33\x39\x2e\x30\x38\x34\x20\x31\x35\x2e\x35\x32\
+\x32\x20\x35\x37\x2e\x30\x33\x37\x20\x31\x35\x2e\x35\x32\x32\x20\
+\x31\x37\x2e\x39\x35\x33\x20\x33\x38\x2e\x38\x39\x37\x20\x31\x37\
+\x2e\x39\x35\x33\x20\x32\x33\x2e\x31\x38\x39\x20\x30\x20\x33\x38\
+\x2e\x38\x39\x37\x2d\x31\x37\x2e\x37\x36\x36\x20\x31\x35\x2e\x37\
+\x30\x39\x2d\x31\x37\x2e\x39\x35\x33\x20\x31\x35\x2e\x37\x30\x39\
+\x2d\x35\x36\x2e\x31\x30\x32\x20\x30\x2d\x33\x36\x2e\x34\x36\x36\
+\x2d\x31\x36\x2e\x32\x37\x2d\x35\x34\x2e\x39\x38\x2d\x31\x36\x2e\
+\x30\x38\x33\x2d\x31\x38\x2e\x35\x31\x34\x2d\x33\x38\x2e\x38\x39\
+\x37\x2d\x31\x38\x2e\x35\x31\x34\x2d\x32\x32\x2e\x34\x34\x31\x20\
+\x30\x2d\x33\x38\x2e\x31\x34\x39\x20\x31\x38\x2e\x33\x32\x37\x2d\
+\x31\x35\x2e\x37\x30\x39\x20\x31\x38\x2e\x31\x34\x2d\x31\x35\x2e\
+\x37\x30\x39\x20\x35\x34\x2e\x30\x34\x35\x7a\x22\x20\x73\x74\x72\
+\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x33\x31\x2e\x39\x31\
+\x36\x22\x20\x61\x72\x69\x61\x2d\x6c\x61\x62\x65\x6c\x3d\x22\x67\
+\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x07\xa9\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x2d\x36\x20\x30\x20\x33\
+\x32\x20\x33\x32\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\
+\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\
+\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\
+\x73\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\
+\x36\x2e\x30\x35\x34\x37\x33\x34\x20\x38\x2e\x36\x35\x31\x31\x30\
+\x34\x31\x68\x35\x2e\x33\x39\x34\x31\x63\x31\x2e\x32\x39\x32\x35\
+\x33\x20\x30\x20\x32\x2e\x33\x36\x32\x35\x30\x35\x20\x31\x2e\x30\
+\x32\x35\x37\x34\x39\x33\x20\x32\x2e\x33\x36\x32\x35\x30\x35\x20\
+\x32\x2e\x33\x36\x32\x35\x30\x34\x39\x76\x38\x2e\x31\x31\x34\x36\
+\x39\x68\x2d\x31\x32\x2e\x38\x33\x39\x37\x76\x2d\x39\x2e\x34\x35\
+\x31\x34\x34\x35\x36\x63\x2d\x2e\x34\x34\x36\x35\x33\x36\x2d\x2e\
+\x31\x33\x34\x31\x30\x33\x35\x2d\x2e\x38\x34\x37\x34\x32\x2d\x2e\
+\x33\x31\x32\x34\x33\x32\x36\x2d\x31\x2e\x31\x31\x34\x32\x30\x30\
+\x35\x2d\x2e\x35\x37\x39\x32\x31\x33\x31\x2d\x2e\x30\x34\x34\x32\
+\x32\x36\x20\x30\x2d\x2e\x30\x34\x34\x32\x32\x36\x2d\x2e\x30\x34\
+\x34\x32\x32\x36\x2d\x2e\x30\x38\x39\x38\x37\x38\x2d\x2e\x30\x34\
+\x34\x32\x32\x36\x20\x30\x20\x30\x20\x30\x20\x2e\x30\x34\x34\x32\
+\x32\x36\x2d\x2e\x30\x34\x34\x32\x32\x36\x2e\x30\x34\x34\x32\x32\
+\x36\x2d\x2e\x33\x31\x32\x34\x33\x32\x32\x2e\x32\x36\x38\x32\x30\
+\x37\x31\x2d\x2e\x36\x36\x39\x30\x39\x30\x35\x2e\x34\x34\x36\x35\
+\x33\x36\x33\x2d\x31\x2e\x30\x36\x39\x39\x37\x34\x35\x2e\x35\x37\
+\x39\x32\x31\x33\x31\x76\x39\x2e\x34\x35\x31\x34\x34\x35\x36\x68\
+\x2d\x31\x32\x2e\x38\x33\x39\x36\x39\x39\x37\x76\x2d\x38\x2e\x31\
+\x31\x34\x36\x39\x63\x30\x2d\x31\x2e\x33\x33\x38\x31\x38\x32\x32\
+\x20\x31\x2e\x30\x32\x35\x37\x34\x39\x33\x2d\x32\x2e\x33\x36\x32\
+\x35\x30\x34\x39\x20\x32\x2e\x33\x31\x38\x32\x37\x39\x31\x2d\x32\
+\x2e\x33\x36\x32\x35\x30\x34\x39\x68\x35\x2e\x34\x33\x39\x37\x35\
+\x32\x38\x63\x2d\x2e\x36\x32\x34\x38\x36\x35\x34\x2d\x2e\x33\x31\
+\x32\x34\x33\x32\x37\x2d\x31\x2e\x32\x30\x34\x30\x37\x38\x35\x2d\
+\x2e\x37\x35\x37\x35\x34\x32\x33\x2d\x31\x2e\x36\x39\x34\x38\x34\
+\x30\x34\x2d\x31\x2e\x31\x35\x39\x38\x35\x32\x39\x2d\x32\x2e\x31\
+\x33\x39\x39\x34\x39\x39\x33\x2d\x32\x2e\x30\x35\x31\x34\x39\x38\
+\x37\x2d\x32\x2e\x35\x34\x30\x38\x33\x33\x38\x38\x2d\x34\x2e\x39\
+\x30\x34\x37\x36\x35\x33\x2d\x2e\x38\x34\x37\x34\x32\x30\x32\x2d\
+\x36\x2e\x35\x30\x39\x37\x32\x37\x37\x32\x2e\x37\x31\x33\x33\x31\
+\x36\x37\x2d\x2e\x36\x32\x34\x38\x36\x35\x33\x38\x20\x31\x2e\x36\
+\x34\x39\x31\x38\x38\x31\x2d\x2e\x39\x38\x31\x35\x32\x33\x37\x31\
+\x20\x32\x2e\x36\x37\x34\x39\x33\x37\x35\x2d\x2e\x39\x38\x31\x35\
+\x32\x33\x37\x31\x20\x31\x2e\x34\x37\x30\x38\x35\x38\x39\x20\x30\
+\x20\x32\x2e\x39\x38\x37\x33\x37\x30\x31\x2e\x35\x37\x39\x32\x31\
+\x33\x31\x32\x20\x34\x2e\x32\x37\x39\x38\x39\x39\x39\x20\x31\x2e\
+\x37\x38\x33\x32\x39\x31\x36\x33\x2e\x37\x31\x33\x33\x31\x36\x36\
+\x2e\x36\x36\x39\x30\x39\x31\x20\x31\x2e\x33\x38\x32\x34\x30\x37\
+\x36\x20\x31\x2e\x36\x30\x34\x39\x36\x32\x35\x20\x31\x2e\x37\x38\
+\x33\x32\x39\x31\x36\x20\x32\x2e\x34\x39\x36\x36\x30\x38\x33\x2e\
+\x34\x34\x36\x35\x33\x36\x34\x2d\x2e\x38\x39\x31\x36\x34\x35\x38\
+\x20\x31\x2e\x31\x31\x34\x32\x30\x30\x34\x2d\x31\x2e\x38\x32\x37\
+\x35\x31\x37\x33\x20\x31\x2e\x38\x32\x37\x35\x31\x37\x34\x2d\x32\
+\x2e\x34\x39\x36\x36\x30\x38\x33\x20\x31\x2e\x32\x34\x38\x33\x30\
+\x34\x2d\x31\x2e\x32\x30\x34\x30\x37\x38\x35\x31\x20\x32\x2e\x38\
+\x35\x33\x32\x36\x36\x2d\x31\x2e\x37\x38\x33\x32\x39\x31\x36\x33\
+\x20\x34\x2e\x32\x37\x39\x39\x2d\x31\x2e\x37\x38\x33\x32\x39\x31\
+\x36\x33\x20\x31\x2e\x30\x36\x39\x39\x37\x35\x20\x30\x20\x32\x2e\
+\x30\x30\x35\x38\x34\x36\x2e\x33\x35\x36\x36\x35\x38\x33\x33\x20\
+\x32\x2e\x36\x37\x34\x39\x33\x37\x2e\x39\x38\x31\x35\x32\x33\x37\
+\x31\x20\x31\x2e\x36\x39\x34\x38\x34\x31\x20\x31\x2e\x36\x30\x34\
+\x39\x36\x32\x34\x32\x20\x31\x2e\x32\x39\x32\x35\x33\x20\x34\x2e\
+\x34\x35\x38\x32\x32\x39\x30\x32\x2d\x2e\x38\x39\x31\x36\x34\x36\
+\x20\x36\x2e\x35\x30\x39\x37\x32\x37\x37\x32\x2d\x2e\x34\x34\x36\
+\x35\x33\x36\x2e\x34\x30\x30\x38\x38\x34\x2d\x31\x2e\x30\x32\x35\
+\x37\x34\x39\x2e\x38\x34\x37\x34\x32\x30\x32\x2d\x31\x2e\x36\x30\
+\x34\x39\x36\x32\x20\x31\x2e\x31\x35\x39\x38\x35\x32\x39\x7a\x6d\
+\x2d\x37\x2e\x39\x33\x36\x33\x36\x31\x35\x2d\x31\x2e\x32\x39\x32\
+\x35\x32\x39\x38\x63\x2e\x31\x37\x38\x33\x32\x39\x32\x2d\x2e\x34\
+\x30\x30\x38\x38\x33\x39\x2d\x2e\x32\x36\x38\x32\x30\x37\x2d\x32\
+\x2e\x34\x35\x32\x33\x38\x32\x36\x2d\x31\x2e\x37\x33\x39\x30\x36\
+\x36\x2d\x33\x2e\x38\x33\x34\x37\x39\x30\x33\x2d\x2e\x37\x35\x37\
+\x35\x34\x32\x33\x2d\x2e\x37\x31\x33\x33\x31\x36\x36\x2d\x31\x2e\
+\x37\x38\x33\x32\x39\x31\x36\x2d\x31\x2e\x31\x31\x34\x32\x30\x30\
+\x36\x2d\x32\x2e\x36\x37\x34\x39\x33\x37\x34\x2d\x31\x2e\x31\x31\
+\x34\x32\x30\x30\x36\x2d\x2e\x32\x36\x38\x32\x30\x37\x31\x20\x30\
+\x2d\x2e\x37\x31\x33\x33\x31\x36\x37\x2e\x30\x34\x34\x32\x32\x36\
+\x2d\x31\x2e\x30\x32\x35\x37\x34\x39\x34\x2e\x33\x31\x32\x34\x33\
+\x32\x37\x2d\x2e\x30\x38\x39\x38\x37\x38\x2e\x30\x38\x39\x38\x37\
+\x38\x2d\x2e\x33\x35\x36\x36\x35\x38\x33\x2e\x32\x36\x38\x32\x30\
+\x37\x31\x2d\x2e\x33\x35\x36\x36\x35\x38\x33\x2e\x37\x35\x37\x35\
+\x34\x32\x33\x20\x30\x20\x2e\x35\x37\x39\x32\x31\x33\x31\x2e\x33\
+\x35\x36\x36\x35\x38\x33\x20\x31\x2e\x34\x37\x30\x38\x35\x38\x39\
+\x20\x31\x2e\x32\x30\x34\x30\x37\x38\x35\x20\x32\x2e\x32\x32\x39\
+\x38\x32\x37\x38\x20\x31\x2e\x30\x36\x39\x39\x37\x35\x20\x31\x2e\
+\x30\x32\x35\x37\x34\x39\x34\x20\x32\x2e\x37\x36\x34\x38\x31\x35\
+\x34\x20\x31\x2e\x37\x33\x39\x30\x36\x36\x20\x34\x2e\x30\x31\x33\
+\x31\x31\x39\x35\x20\x31\x2e\x37\x33\x39\x30\x36\x36\x2e\x34\x30\
+\x30\x38\x38\x33\x39\x20\x30\x20\x2e\x35\x37\x39\x32\x31\x33\x31\
+\x2d\x2e\x30\x38\x39\x38\x37\x38\x2e\x35\x37\x39\x32\x31\x33\x31\
+\x2d\x2e\x30\x38\x39\x38\x37\x38\x7a\x6d\x33\x2e\x33\x38\x38\x32\
+\x35\x34\x35\x20\x30\x73\x2e\x32\x32\x32\x35\x35\x34\x2e\x30\x38\
+\x39\x38\x37\x38\x2e\x35\x37\x39\x32\x31\x33\x2e\x30\x38\x39\x38\
+\x37\x38\x63\x31\x2e\x32\x34\x38\x33\x30\x34\x20\x30\x20\x32\x2e\
+\x39\x34\x33\x31\x34\x34\x2d\x2e\x37\x31\x33\x33\x31\x36\x36\x20\
+\x34\x2e\x30\x31\x33\x31\x31\x39\x2d\x31\x2e\x37\x33\x39\x30\x36\
+\x36\x2e\x38\x34\x37\x34\x32\x2d\x2e\x37\x35\x37\x35\x34\x32\x32\
+\x20\x31\x2e\x31\x31\x34\x32\x30\x31\x2d\x31\x2e\x36\x34\x39\x31\
+\x38\x38\x31\x20\x31\x2e\x31\x31\x34\x32\x30\x31\x2d\x32\x2e\x32\
+\x32\x39\x38\x32\x37\x38\x20\x30\x2d\x2e\x34\x39\x30\x37\x36\x31\
+\x39\x2d\x2e\x32\x32\x32\x35\x35\x35\x2d\x2e\x36\x36\x39\x30\x39\
+\x31\x2d\x2e\x32\x36\x38\x32\x30\x37\x2d\x2e\x37\x35\x37\x35\x34\
+\x32\x33\x2d\x2e\x33\x31\x32\x34\x33\x33\x2d\x2e\x32\x36\x38\x32\
+\x30\x37\x2d\x2e\x38\x30\x33\x31\x39\x35\x2d\x2e\x33\x31\x32\x34\
+\x33\x32\x37\x2d\x31\x2e\x30\x36\x39\x39\x37\x35\x2d\x2e\x33\x31\
+\x32\x34\x33\x32\x37\x2d\x2e\x38\x34\x37\x34\x32\x20\x30\x2d\x31\
+\x2e\x39\x31\x37\x33\x39\x35\x2e\x34\x30\x30\x38\x38\x34\x2d\x32\
+\x2e\x36\x37\x34\x39\x33\x38\x20\x31\x2e\x31\x31\x34\x32\x30\x30\
+\x36\x2d\x31\x2e\x34\x32\x36\x36\x33\x33\x20\x31\x2e\x33\x38\x32\
+\x34\x30\x37\x36\x2d\x31\x2e\x39\x31\x37\x33\x39\x35\x20\x33\x2e\
+\x33\x38\x38\x32\x35\x34\x2d\x31\x2e\x36\x39\x34\x38\x34\x20\x33\
+\x2e\x38\x37\x39\x30\x31\x35\x39\x76\x2d\x2e\x30\x34\x34\x32\x32\
+\x35\x37\x7a\x6d\x2d\x32\x2e\x38\x35\x33\x32\x36\x37\x20\x32\x34\
+\x2e\x36\x30\x39\x34\x32\x34\x37\x68\x2d\x31\x30\x2e\x35\x32\x31\
+\x34\x32\x30\x36\x63\x2d\x31\x2e\x32\x39\x32\x35\x32\x39\x38\x20\
+\x30\x2d\x32\x2e\x33\x31\x38\x32\x37\x39\x31\x2d\x31\x2e\x30\x32\
+\x35\x37\x35\x2d\x32\x2e\x33\x31\x38\x32\x37\x39\x31\x2d\x32\x2e\
+\x33\x31\x38\x32\x37\x39\x76\x2d\x38\x2e\x31\x35\x38\x39\x31\x36\
+\x68\x31\x32\x2e\x38\x33\x39\x36\x39\x39\x37\x7a\x6d\x31\x32\x2e\
+\x37\x39\x35\x34\x37\x34\x20\x30\x68\x2d\x31\x30\x2e\x34\x37\x37\
+\x31\x39\x35\x76\x2d\x31\x30\x2e\x34\x37\x37\x31\x39\x35\x68\x31\
+\x32\x2e\x38\x33\x39\x37\x76\x38\x2e\x31\x35\x38\x39\x31\x36\x63\
+\x30\x20\x31\x2e\x32\x39\x32\x35\x32\x39\x2d\x31\x2e\x30\x36\x39\
+\x39\x37\x35\x20\x32\x2e\x33\x31\x38\x32\x37\x39\x2d\x32\x2e\x33\
+\x36\x32\x35\x30\x35\x20\x32\x2e\x33\x31\x38\x32\x37\x39\x7a\x22\
+\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x06\x2e\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x31\x20\x38\x30\
+\x30\x20\x38\x30\x30\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\
+\x30\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\
+\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\
+\x2f\x73\x76\x67\x22\x3e\x3c\x67\x20\x73\x74\x72\x6f\x6b\x65\x2d\
+\x77\x69\x64\x74\x68\x3d\x22\x2e\x30\x32\x36\x38\x37\x35\x22\x20\
+\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\x74\x72\x69\
+\x78\x28\x33\x37\x2e\x32\x30\x39\x32\x37\x38\x20\x30\x20\x30\x20\
+\x33\x37\x2e\x32\x30\x39\x32\x37\x38\x20\x2d\x34\x36\x2e\x35\x31\
+\x31\x35\x39\x38\x20\x2d\x33\x30\x2e\x38\x32\x31\x31\x32\x38\x29\
+\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x37\x2e\x34\
+\x31\x36\x20\x32\x2e\x36\x32\x34\x31\x32\x63\x2e\x33\x34\x34\x37\
+\x2d\x2e\x32\x32\x39\x37\x37\x2e\x34\x33\x37\x38\x2d\x2e\x36\x39\
+\x35\x34\x32\x2e\x32\x30\x38\x2d\x31\x2e\x30\x34\x30\x30\x37\x2d\
+\x2e\x32\x32\x39\x37\x2d\x2e\x33\x34\x34\x36\x34\x2d\x2e\x36\x39\
+\x35\x34\x2d\x2e\x34\x33\x37\x37\x37\x2d\x31\x2e\x30\x34\x2d\x2e\
+\x32\x30\x38\x30\x31\x6c\x2d\x32\x2e\x39\x31\x35\x33\x20\x31\x2e\
+\x39\x34\x33\x35\x31\x63\x2d\x2e\x35\x31\x36\x2d\x2e\x32\x30\x36\
+\x31\x32\x2d\x31\x2e\x30\x37\x39\x2d\x2e\x33\x31\x39\x34\x39\x2d\
+\x31\x2e\x36\x36\x38\x36\x2d\x2e\x33\x31\x39\x34\x39\x73\x2d\x31\
+\x2e\x31\x35\x32\x37\x2e\x31\x31\x33\x33\x39\x2d\x31\x2e\x36\x36\
+\x38\x37\x2e\x33\x31\x39\x35\x36\x6c\x2d\x32\x2e\x39\x31\x35\x33\
+\x37\x2d\x31\x2e\x39\x34\x33\x35\x38\x63\x2d\x2e\x33\x34\x34\x36\
+\x35\x2d\x2e\x32\x32\x39\x37\x36\x2d\x2e\x38\x31\x30\x33\x2d\x2e\
+\x31\x33\x36\x36\x33\x2d\x31\x2e\x30\x34\x30\x30\x37\x2e\x32\x30\
+\x38\x30\x31\x2d\x2e\x32\x32\x39\x37\x36\x2e\x33\x34\x34\x36\x35\
+\x2d\x2e\x31\x33\x36\x36\x33\x2e\x38\x31\x30\x33\x2e\x32\x30\x38\
+\x30\x31\x20\x31\x2e\x30\x34\x30\x30\x37\x6c\x32\x2e\x33\x35\x39\
+\x37\x33\x20\x31\x2e\x35\x37\x33\x31\x35\x63\x2d\x2e\x36\x39\x35\
+\x33\x39\x2e\x36\x34\x33\x38\x32\x2d\x31\x2e\x31\x38\x37\x30\x36\
+\x20\x31\x2e\x35\x30\x34\x35\x34\x2d\x31\x2e\x33\x36\x37\x35\x33\
+\x20\x32\x2e\x34\x37\x34\x36\x33\x2e\x34\x33\x35\x31\x31\x2d\x2e\
+\x31\x31\x32\x31\x37\x2e\x38\x39\x31\x33\x32\x2d\x2e\x31\x37\x31\
+\x38\x34\x20\x31\x2e\x33\x36\x31\x34\x36\x2d\x2e\x31\x37\x31\x38\
+\x34\x68\x36\x2e\x31\x32\x34\x39\x37\x63\x2e\x34\x37\x30\x32\x20\
+\x30\x20\x2e\x39\x32\x36\x34\x2e\x30\x35\x39\x36\x37\x20\x31\x2e\
+\x33\x36\x31\x35\x2e\x31\x37\x31\x38\x34\x2d\x2e\x31\x38\x30\x35\
+\x2d\x2e\x39\x37\x30\x31\x34\x2d\x2e\x36\x37\x32\x32\x2d\x31\x2e\
+\x38\x33\x30\x39\x2d\x31\x2e\x33\x36\x37\x37\x2d\x32\x2e\x34\x37\
+\x34\x37\x33\x7a\x22\x2f\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\
+\x6d\x31\x2e\x32\x35\x20\x31\x34\x2e\x30\x30\x30\x31\x63\x30\x2d\
+\x2e\x34\x31\x34\x32\x2e\x33\x33\x35\x37\x39\x2d\x2e\x37\x35\x2e\
+\x37\x35\x2d\x2e\x37\x35\x68\x33\x76\x2d\x31\x2e\x33\x31\x32\x35\
+\x63\x30\x2d\x2e\x38\x33\x35\x37\x2e\x32\x36\x30\x33\x34\x2d\x31\
+\x2e\x36\x31\x30\x36\x2e\x37\x30\x34\x33\x35\x2d\x32\x2e\x32\x34\
+\x38\x30\x31\x6c\x2d\x32\x2e\x34\x38\x32\x39\x34\x2d\x2e\x39\x39\
+\x33\x33\x35\x63\x2d\x2e\x33\x38\x34\x35\x37\x2d\x2e\x31\x35\x33\
+\x38\x36\x2d\x2e\x35\x37\x31\x36\x31\x2d\x2e\x35\x39\x30\x33\x35\
+\x2d\x2e\x34\x31\x37\x37\x35\x2d\x2e\x39\x37\x34\x39\x33\x73\x2e\
+\x35\x39\x30\x33\x35\x2d\x2e\x35\x37\x31\x36\x31\x2e\x39\x37\x34\
+\x39\x33\x2d\x2e\x34\x31\x37\x37\x35\x6c\x33\x2e\x31\x33\x36\x35\
+\x35\x20\x31\x2e\x32\x35\x34\x38\x35\x63\x2e\x35\x39\x31\x31\x2d\
+\x2e\x33\x35\x34\x35\x33\x20\x31\x2e\x32\x38\x32\x39\x33\x2d\x2e\
+\x35\x35\x38\x33\x35\x20\x32\x2e\x30\x32\x32\x33\x36\x2d\x2e\x35\
+\x35\x38\x33\x35\x68\x36\x2e\x31\x32\x35\x63\x2e\x37\x33\x39\x34\
+\x20\x30\x20\x31\x2e\x34\x33\x31\x33\x2e\x32\x30\x33\x38\x32\x20\
+\x32\x2e\x30\x32\x32\x34\x2e\x35\x35\x38\x33\x35\x6c\x33\x2e\x31\
+\x33\x36\x35\x2d\x31\x2e\x32\x35\x34\x38\x35\x63\x2e\x33\x38\x34\
+\x36\x2d\x2e\x31\x35\x33\x38\x36\x2e\x38\x32\x31\x31\x2e\x30\x33\
+\x33\x31\x37\x2e\x39\x37\x34\x39\x2e\x34\x31\x37\x37\x35\x2e\x31\
+\x35\x33\x39\x2e\x33\x38\x34\x35\x38\x2d\x2e\x30\x33\x33\x31\x2e\
+\x38\x32\x31\x30\x37\x2d\x2e\x34\x31\x37\x37\x2e\x39\x37\x34\x39\
+\x33\x6c\x2d\x32\x2e\x34\x38\x32\x39\x2e\x39\x39\x33\x33\x35\x63\
+\x2e\x34\x34\x34\x2e\x36\x33\x37\x34\x31\x2e\x37\x30\x34\x33\x20\
+\x31\x2e\x34\x31\x32\x33\x31\x2e\x37\x30\x34\x33\x20\x32\x2e\x32\
+\x34\x38\x30\x31\x76\x31\x2e\x33\x31\x32\x35\x68\x33\x63\x2e\x34\
+\x31\x34\x32\x20\x30\x20\x2e\x37\x35\x2e\x33\x33\x35\x38\x2e\x37\
+\x35\x2e\x37\x35\x73\x2d\x2e\x33\x33\x35\x38\x2e\x37\x35\x2d\x2e\
+\x37\x35\x2e\x37\x35\x68\x2d\x33\x76\x2e\x32\x35\x63\x30\x20\x31\
+\x2e\x31\x38\x30\x37\x2d\x2e\x32\x39\x32\x33\x20\x32\x2e\x32\x39\
+\x33\x31\x2d\x2e\x38\x30\x38\x35\x20\x33\x2e\x32\x36\x38\x38\x6c\
+\x32\x2e\x35\x38\x37\x31\x20\x31\x2e\x30\x33\x35\x63\x2e\x33\x38\
+\x34\x36\x2e\x31\x35\x33\x39\x2e\x35\x37\x31\x36\x2e\x35\x39\x30\
+\x34\x2e\x34\x31\x37\x37\x2e\x39\x37\x35\x2d\x2e\x31\x35\x33\x38\
+\x2e\x33\x38\x34\x35\x2d\x2e\x35\x39\x30\x33\x2e\x35\x37\x31\x36\
+\x2d\x2e\x39\x37\x34\x39\x2e\x34\x31\x37\x37\x6c\x2d\x32\x2e\x38\
+\x39\x32\x36\x2d\x31\x2e\x31\x35\x37\x32\x63\x2d\x31\x2e\x31\x33\
+\x31\x34\x20\x31\x2e\x33\x32\x37\x2d\x32\x2e\x37\x34\x39\x39\x20\
+\x32\x2e\x32\x32\x36\x31\x2d\x34\x2e\x35\x37\x38\x38\x20\x32\x2e\
+\x34\x32\x31\x76\x2d\x36\x2e\x39\x36\x30\x33\x63\x30\x2d\x2e\x34\
+\x31\x34\x33\x2d\x2e\x33\x33\x35\x38\x2d\x2e\x37\x35\x2d\x2e\x37\
+\x35\x2d\x2e\x37\x35\x73\x2d\x2e\x37\x35\x2e\x33\x33\x35\x37\x2d\
+\x2e\x37\x35\x2e\x37\x35\x76\x36\x2e\x39\x36\x30\x33\x63\x2d\x31\
+\x2e\x38\x32\x38\x39\x31\x2d\x2e\x31\x39\x34\x39\x2d\x33\x2e\x34\
+\x34\x37\x33\x35\x2d\x31\x2e\x30\x39\x34\x2d\x34\x2e\x35\x37\x38\
+\x38\x35\x2d\x32\x2e\x34\x32\x31\x6c\x2d\x32\x2e\x38\x39\x32\x35\
+\x36\x20\x31\x2e\x31\x35\x37\x32\x63\x2d\x2e\x33\x38\x34\x35\x38\
+\x2e\x31\x35\x33\x39\x2d\x2e\x38\x32\x31\x30\x37\x2d\x2e\x30\x33\
+\x33\x32\x2d\x2e\x39\x37\x34\x39\x33\x2d\x2e\x34\x31\x37\x37\x2d\
+\x2e\x31\x35\x33\x38\x36\x2d\x2e\x33\x38\x34\x36\x2e\x30\x33\x33\
+\x31\x38\x2d\x2e\x38\x32\x31\x31\x2e\x34\x31\x37\x37\x35\x2d\x2e\
+\x39\x37\x35\x6c\x32\x2e\x35\x38\x37\x31\x31\x2d\x31\x2e\x30\x33\
+\x35\x63\x2d\x2e\x35\x31\x36\x32\x31\x2d\x2e\x39\x37\x35\x37\x2d\
+\x2e\x38\x30\x38\x35\x32\x2d\x32\x2e\x30\x38\x38\x31\x2d\x2e\x38\
+\x30\x38\x35\x32\x2d\x33\x2e\x32\x36\x38\x38\x76\x2d\x2e\x32\x35\
+\x68\x2d\x33\x63\x2d\x2e\x34\x31\x34\x32\x31\x20\x30\x2d\x2e\x37\
+\x35\x2d\x2e\x33\x33\x35\x38\x2d\x2e\x37\x35\x2d\x2e\x37\x35\x7a\
+\x22\x2f\x3e\x3c\x2f\x67\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x02\x53\
+\x3c\
+\x73\x76\x67\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\x6e\x65\x22\x20\
+\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\x20\x76\x69\x65\
+\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\x34\x20\x32\x34\x22\
+\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\x20\x78\x6d\x6c\
+\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\
+\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\
+\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x32\x2e\x39\x39\x39\x30\
+\x32\x20\x33\x20\x31\x37\x2e\x39\x39\x39\x39\x38\x20\x31\x38\x6d\
+\x2d\x31\x31\x2e\x31\x35\x35\x37\x2d\x31\x31\x2e\x30\x38\x36\x33\
+\x36\x63\x2d\x2e\x35\x32\x32\x36\x34\x2e\x35\x33\x39\x39\x36\x2d\
+\x2e\x38\x34\x34\x32\x38\x20\x31\x2e\x32\x37\x35\x35\x36\x2d\x2e\
+\x38\x34\x34\x32\x38\x20\x32\x2e\x30\x38\x36\x33\x36\x20\x30\x20\
+\x31\x2e\x36\x35\x36\x39\x20\x31\x2e\x33\x34\x33\x31\x38\x20\x33\
+\x20\x32\x2e\x39\x39\x39\x39\x38\x20\x33\x20\x2e\x38\x32\x32\x35\
+\x20\x30\x20\x31\x2e\x35\x36\x37\x37\x2d\x2e\x33\x33\x31\x20\x32\
+\x2e\x31\x30\x39\x36\x2d\x2e\x38\x36\x37\x6d\x2d\x37\x2e\x36\x30\
+\x39\x35\x38\x2d\x37\x2e\x34\x38\x35\x38\x35\x63\x2d\x31\x2e\x38\
+\x39\x39\x33\x20\x31\x2e\x32\x35\x33\x31\x39\x2d\x33\x2e\x33\x34\
+\x35\x39\x37\x20\x33\x2e\x31\x33\x36\x37\x39\x2d\x34\x2e\x30\x34\
+\x31\x39\x39\x20\x35\x2e\x33\x35\x32\x38\x35\x20\x31\x2e\x32\x37\
+\x34\x32\x35\x20\x34\x2e\x30\x35\x37\x31\x20\x35\x2e\x30\x36\x34\
+\x35\x36\x20\x37\x20\x39\x2e\x35\x34\x32\x31\x37\x20\x37\x20\x31\
+\x2e\x39\x38\x38\x39\x20\x30\x20\x33\x2e\x38\x34\x32\x32\x2d\x2e\
+\x35\x38\x30\x36\x20\x35\x2e\x33\x39\x39\x36\x2d\x31\x2e\x35\x38\
+\x31\x36\x6d\x2d\x36\x2e\x33\x39\x39\x38\x2d\x31\x32\x2e\x33\x36\
+\x39\x30\x31\x63\x2e\x33\x32\x39\x2d\x2e\x30\x33\x32\x36\x36\x2e\
+\x36\x36\x32\x37\x2d\x2e\x30\x34\x39\x33\x39\x20\x31\x2e\x30\x30\
+\x30\x32\x2d\x2e\x30\x34\x39\x33\x39\x20\x34\x2e\x34\x37\x37\x37\
+\x20\x30\x20\x38\x2e\x32\x36\x38\x20\x32\x2e\x39\x34\x32\x39\x31\
+\x20\x39\x2e\x35\x34\x32\x32\x20\x37\x2d\x2e\x32\x38\x30\x37\x2e\
+\x38\x39\x34\x2d\x2e\x36\x38\x33\x37\x20\x31\x2e\x37\x33\x33\x38\
+\x2d\x31\x2e\x31\x38\x39\x32\x20\x32\x2e\x35\x22\x20\x73\x74\x72\
+\x6f\x6b\x65\x3d\x22\x23\x30\x30\x30\x22\x20\x73\x74\x72\x6f\x6b\
+\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\x22\x72\x6f\x75\x6e\x64\
+\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x6a\x6f\x69\
+\x6e\x3d\x22\x72\x6f\x75\x6e\x64\x22\x20\x73\x74\x72\x6f\x6b\x65\
+\x2d\x77\x69\x64\x74\x68\x3d\x22\x32\x22\x2f\x3e\x3c\x2f\x73\x76\
+\x67\x3e\
+\x00\x00\x00\x99\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x31\x31\x2e\x36\x37\x20\x32\x31\x31\x2e\x36\x37\x22\x20\x78\x6d\
+\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\
+\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\
+\x3e\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x06\x32\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\
+\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\
+\x31\x32\x20\x35\x31\x32\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\
+\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\
+\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\x0a\x20\x3c\x70\x61\
+\x74\x68\x20\x64\x3d\x22\x6d\x32\x35\x37\x2e\x38\x38\x20\x32\x32\
+\x39\x2e\x37\x32\x71\x31\x39\x2e\x33\x37\x32\x2d\x33\x38\x2e\x35\
+\x34\x36\x20\x32\x37\x2e\x36\x32\x31\x2d\x38\x32\x2e\x37\x39\x34\
+\x20\x31\x32\x2e\x32\x30\x36\x2d\x36\x33\x2e\x35\x38\x35\x20\x32\
+\x33\x2e\x37\x35\x33\x2d\x38\x33\x2e\x35\x38\x35\x20\x31\x36\x2e\
+\x32\x32\x39\x2d\x32\x38\x2e\x31\x30\x39\x20\x33\x37\x2e\x36\x32\
+\x38\x2d\x33\x35\x2e\x32\x31\x33\x20\x32\x31\x2e\x39\x34\x2d\x36\
+\x2e\x37\x39\x32\x37\x20\x34\x31\x2e\x34\x20\x34\x2e\x34\x34\x32\
+\x34\x20\x31\x36\x2e\x37\x35\x37\x20\x39\x2e\x36\x37\x34\x37\x20\
+\x32\x30\x2e\x37\x36\x33\x20\x33\x31\x2e\x34\x34\x38\x20\x34\x2e\
+\x30\x30\x36\x33\x20\x32\x31\x2e\x37\x37\x33\x2d\x31\x31\x2e\x35\
+\x39\x38\x20\x34\x38\x2e\x38\x2d\x31\x34\x2e\x30\x34\x34\x20\x32\
+\x34\x2e\x33\x32\x35\x2d\x35\x33\x2e\x39\x31\x38\x20\x35\x39\x2e\
+\x36\x38\x33\x2d\x33\x39\x2e\x30\x32\x31\x20\x33\x35\x2e\x31\x33\
+\x2d\x36\x33\x2e\x34\x38\x36\x20\x37\x30\x2e\x30\x31\x35\x20\x34\
+\x30\x2e\x36\x35\x33\x2d\x31\x2e\x37\x35\x34\x35\x20\x38\x30\x2e\
+\x30\x34\x32\x2d\x31\x35\x2e\x30\x35\x20\x36\x31\x2e\x34\x31\x32\
+\x2d\x32\x31\x2e\x34\x38\x32\x20\x38\x35\x2e\x31\x38\x2d\x32\x31\
+\x2e\x34\x35\x33\x20\x32\x33\x2e\x37\x36\x38\x20\x30\x2e\x30\x32\
+\x38\x35\x20\x34\x32\x2e\x31\x34\x37\x20\x31\x30\x2e\x36\x33\x39\
+\x20\x31\x37\x2e\x38\x33\x38\x20\x31\x30\x2e\x32\x39\x39\x20\x32\
+\x32\x2e\x35\x35\x32\x20\x32\x39\x2e\x35\x39\x37\x20\x35\x2e\x35\
+\x36\x36\x38\x20\x31\x39\x2e\x30\x37\x2d\x34\x2e\x31\x30\x38\x20\
+\x33\x35\x2e\x38\x32\x37\x2d\x31\x31\x2e\x35\x34\x37\x20\x32\x30\
+\x2d\x33\x38\x2e\x34\x33\x36\x20\x32\x35\x2e\x33\x37\x37\x2d\x32\
+\x36\x2e\x38\x38\x39\x20\x35\x2e\x33\x37\x37\x31\x2d\x31\x30\x37\
+\x2e\x32\x39\x2d\x32\x30\x2e\x31\x34\x32\x2d\x34\x36\x2e\x39\x32\
+\x38\x2d\x31\x34\x2e\x38\x34\x31\x2d\x38\x31\x2e\x33\x36\x32\x2d\
+\x31\x38\x2e\x38\x36\x36\x20\x31\x39\x2e\x36\x38\x32\x20\x33\x30\
+\x2e\x38\x32\x33\x20\x35\x35\x2e\x38\x35\x34\x20\x36\x31\x2e\x37\
+\x39\x38\x20\x35\x38\x2e\x35\x34\x31\x20\x34\x39\x2e\x36\x35\x35\
+\x20\x36\x38\x2e\x32\x34\x32\x20\x37\x39\x2e\x30\x34\x20\x31\x30\
+\x2e\x32\x34\x32\x20\x32\x39\x2e\x36\x39\x37\x2d\x31\x2e\x39\x32\
+\x39\x34\x20\x35\x30\x2e\x37\x37\x39\x2d\x39\x2e\x33\x36\x32\x36\
+\x20\x31\x36\x2e\x32\x31\x37\x2d\x32\x38\x2e\x36\x36\x31\x20\x32\
+\x30\x2e\x39\x33\x31\x2d\x31\x38\x2e\x37\x35\x38\x20\x35\x2e\x30\
+\x32\x36\x32\x2d\x33\x34\x2e\x39\x37\x35\x2d\x34\x2e\x33\x33\x36\
+\x34\x2d\x31\x36\x2e\x32\x31\x37\x2d\x39\x2e\x33\x36\x32\x36\x2d\
+\x32\x39\x2e\x36\x36\x33\x2d\x33\x32\x2e\x32\x36\x31\x2d\x31\x32\
+\x2e\x39\x30\x36\x2d\x32\x32\x2e\x35\x38\x37\x2d\x32\x33\x2e\x36\
+\x33\x38\x2d\x38\x31\x2e\x33\x39\x36\x2d\x36\x2e\x38\x37\x30\x33\
+\x2d\x33\x39\x2e\x32\x38\x33\x2d\x32\x36\x2e\x34\x32\x34\x2d\x38\
+\x31\x2e\x35\x36\x33\x2d\x31\x36\x2e\x37\x30\x38\x20\x33\x31\x2e\
+\x34\x33\x36\x2d\x32\x36\x2e\x32\x36\x36\x20\x37\x34\x2e\x32\x30\
+\x36\x2d\x31\x37\x2e\x33\x36\x36\x20\x37\x35\x2e\x30\x32\x2d\x33\
+\x30\x2e\x37\x38\x36\x20\x39\x38\x2e\x32\x36\x34\x2d\x31\x32\x2e\
+\x34\x38\x33\x20\x32\x31\x2e\x36\x32\x32\x2d\x33\x34\x2e\x31\x39\
+\x35\x20\x32\x39\x2e\x32\x36\x37\x2d\x32\x31\x2e\x34\x20\x37\x2e\
+\x31\x30\x34\x38\x2d\x33\x35\x2e\x39\x39\x34\x2d\x31\x2e\x33\x32\
+\x31\x36\x2d\x32\x30\x2d\x31\x31\x2e\x35\x34\x37\x2d\x32\x37\x2e\
+\x31\x36\x36\x2d\x33\x36\x2e\x35\x38\x36\x2d\x34\x2e\x37\x39\x37\
+\x37\x2d\x31\x37\x2e\x39\x30\x35\x20\x39\x2e\x35\x35\x38\x32\x2d\
+\x34\x32\x2e\x37\x37\x31\x20\x31\x34\x2e\x39\x38\x2d\x32\x35\x2e\
+\x39\x34\x36\x20\x34\x38\x2e\x33\x32\x33\x2d\x35\x34\x2e\x39\x38\
+\x35\x20\x33\x33\x2e\x36\x35\x35\x2d\x32\x39\x2e\x35\x37\x39\x20\
+\x34\x34\x2e\x37\x2d\x34\x31\x2e\x32\x32\x31\x20\x31\x31\x2e\x33\
+\x35\x38\x2d\x31\x32\x2e\x31\x38\x32\x20\x32\x39\x2e\x36\x36\x35\
+\x2d\x33\x37\x2e\x36\x34\x39\x2d\x34\x34\x2e\x30\x36\x34\x20\x32\
+\x2e\x36\x36\x38\x34\x2d\x38\x32\x2e\x38\x32\x38\x20\x31\x34\x2e\
+\x38\x38\x33\x2d\x36\x35\x2e\x30\x35\x31\x20\x32\x31\x2e\x35\x34\
+\x33\x2d\x39\x31\x2e\x39\x31\x38\x20\x32\x31\x2e\x38\x38\x38\x2d\
+\x31\x39\x2e\x30\x34\x38\x20\x30\x2e\x35\x33\x34\x35\x34\x2d\x33\
+\x34\x2e\x31\x38\x33\x2d\x38\x2e\x32\x30\x33\x39\x2d\x31\x38\x2e\
+\x33\x37\x39\x2d\x31\x30\x2e\x36\x31\x31\x2d\x32\x34\x2e\x31\x37\
+\x34\x2d\x33\x30\x2e\x35\x33\x34\x2d\x35\x2e\x37\x39\x35\x32\x2d\
+\x31\x39\x2e\x39\x32\x33\x20\x32\x2e\x39\x34\x33\x32\x2d\x33\x35\
+\x2e\x30\x35\x38\x20\x37\x2e\x38\x30\x32\x32\x2d\x31\x33\x2e\x35\
+\x31\x34\x20\x32\x37\x2e\x30\x34\x2d\x32\x31\x2e\x38\x36\x37\x20\
+\x32\x30\x2e\x30\x39\x2d\x38\x2e\x35\x38\x31\x36\x20\x34\x37\x2e\
+\x38\x37\x2d\x35\x2e\x35\x31\x35\x39\x20\x31\x38\x2e\x33\x34\x20\
+\x31\x2e\x39\x33\x39\x37\x20\x37\x36\x2e\x34\x37\x34\x20\x32\x31\
+\x2e\x30\x38\x39\x20\x33\x37\x2e\x35\x37\x31\x20\x31\x32\x2e\x33\
+\x32\x32\x20\x37\x37\x2e\x32\x36\x36\x20\x31\x37\x2e\x32\x32\x32\
+\x2d\x32\x30\x2e\x37\x36\x33\x2d\x33\x31\x2e\x34\x34\x38\x2d\x35\
+\x36\x2e\x36\x32\x33\x2d\x36\x32\x2e\x39\x36\x32\x2d\x35\x38\x2e\
+\x33\x37\x33\x2d\x35\x32\x2e\x34\x34\x31\x2d\x36\x37\x2e\x34\x39\
+\x36\x2d\x37\x32\x2e\x38\x34\x33\x2d\x31\x34\x2e\x30\x32\x36\x2d\
+\x33\x31\x2e\x38\x38\x32\x20\x30\x2e\x36\x34\x32\x31\x39\x2d\x35\
+\x37\x2e\x32\x38\x38\x20\x38\x2e\x34\x32\x36\x33\x2d\x31\x34\x2e\
+\x35\x39\x35\x20\x32\x37\x2e\x31\x38\x34\x2d\x31\x39\x2e\x36\x32\
+\x31\x20\x31\x39\x2e\x36\x31\x31\x2d\x35\x2e\x32\x35\x34\x37\x20\
+\x33\x35\x2e\x38\x32\x37\x20\x34\x2e\x31\x30\x38\x20\x31\x37\x2e\
+\x38\x33\x38\x20\x31\x30\x2e\x32\x39\x39\x20\x33\x31\x2e\x32\x38\
+\x35\x20\x33\x33\x2e\x31\x39\x38\x20\x31\x33\x2e\x34\x34\x37\x20\
+\x32\x32\x2e\x38\x39\x39\x20\x32\x33\x2e\x32\x30\x33\x20\x37\x34\
+\x2e\x36\x35\x39\x20\x31\x30\x2e\x30\x36\x39\x20\x35\x31\x2e\x32\
+\x31\x39\x20\x32\x39\x2e\x39\x35\x37\x20\x38\x37\x2e\x39\x32\x38\
+\x7a\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\
+\x22\x31\x30\x36\x2e\x35\x32\x22\x20\x61\x72\x69\x61\x2d\x6c\x61\
+\x62\x65\x6c\x3d\x22\x2a\x22\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\
+\x0a\
+\x00\x00\x04\x40\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\
+\x22\x38\x30\x30\x70\x78\x22\x20\x66\x69\x6c\x6c\x3d\x22\x23\x30\
+\x30\x30\x30\x30\x30\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\
+\x31\x2e\x31\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\
+\x30\x20\x35\x31\x32\x20\x35\x31\x32\x22\x20\x78\x6d\x6c\x3a\x73\
+\x70\x61\x63\x65\x3d\x22\x70\x72\x65\x73\x65\x72\x76\x65\x22\x20\
+\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\
+\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\
+\x67\x22\x3e\x0a\x0a\x09\x0a\x09\x09\x3c\x70\x61\x74\x68\x20\x64\
+\x3d\x22\x6d\x34\x36\x39\x2e\x33\x33\x20\x36\x34\x76\x2d\x32\x31\
+\x2e\x33\x33\x33\x63\x30\x2d\x32\x33\x2e\x35\x33\x31\x2d\x31\x39\
+\x2e\x31\x33\x36\x2d\x34\x32\x2e\x36\x36\x37\x2d\x34\x32\x2e\x36\
+\x36\x36\x2d\x34\x32\x2e\x36\x36\x37\x68\x2d\x33\x34\x31\x2e\x33\
+\x33\x63\x2d\x32\x33\x2e\x35\x33\x20\x30\x2d\x34\x32\x2e\x36\x36\
+\x36\x20\x31\x39\x2e\x31\x33\x36\x2d\x34\x32\x2e\x36\x36\x36\x20\
+\x34\x32\x2e\x36\x36\x37\x76\x32\x31\x2e\x33\x33\x33\x63\x30\x20\
+\x32\x33\x2e\x35\x33\x31\x20\x31\x39\x2e\x31\x33\x36\x20\x34\x32\
+\x2e\x36\x36\x37\x20\x34\x32\x2e\x36\x36\x37\x20\x34\x32\x2e\x36\
+\x36\x37\x76\x31\x32\x38\x63\x2d\x32\x33\x2e\x35\x33\x31\x20\x30\
+\x2d\x34\x32\x2e\x36\x36\x37\x20\x31\x39\x2e\x31\x33\x36\x2d\x34\
+\x32\x2e\x36\x36\x37\x20\x34\x32\x2e\x36\x36\x37\x76\x32\x31\x2e\
+\x33\x33\x33\x63\x30\x20\x32\x33\x2e\x35\x33\x31\x20\x31\x39\x2e\
+\x31\x33\x36\x20\x34\x32\x2e\x36\x36\x37\x20\x34\x32\x2e\x36\x36\
+\x37\x20\x34\x32\x2e\x36\x36\x37\x76\x31\x32\x38\x63\x2d\x31\x65\
+\x2d\x33\x20\x32\x33\x2e\x35\x33\x20\x31\x39\x2e\x31\x33\x35\x20\
+\x34\x32\x2e\x36\x36\x36\x20\x34\x32\x2e\x36\x36\x36\x20\x34\x32\
+\x2e\x36\x36\x36\x68\x32\x35\x36\x63\x32\x33\x2e\x35\x33\x31\x20\
+\x30\x20\x34\x32\x2e\x36\x36\x37\x2d\x31\x39\x2e\x31\x33\x36\x20\
+\x34\x32\x2e\x36\x36\x37\x2d\x34\x32\x2e\x36\x36\x37\x76\x2d\x31\
+\x32\x38\x63\x32\x33\x2e\x35\x33\x31\x20\x30\x20\x34\x32\x2e\x36\
+\x36\x37\x2d\x31\x39\x2e\x31\x33\x36\x20\x34\x32\x2e\x36\x36\x37\
+\x2d\x34\x32\x2e\x36\x36\x37\x76\x2d\x32\x31\x2e\x33\x33\x33\x63\
+\x30\x2d\x32\x33\x2e\x35\x33\x31\x2d\x31\x39\x2e\x31\x33\x36\x2d\
+\x34\x32\x2e\x36\x36\x37\x2d\x34\x32\x2e\x36\x36\x37\x2d\x34\x32\
+\x2e\x36\x36\x37\x76\x2d\x31\x32\x38\x63\x32\x33\x2e\x35\x33\x20\
+\x31\x65\x2d\x33\x20\x34\x32\x2e\x36\x36\x36\x2d\x31\x39\x2e\x31\
+\x33\x35\x20\x34\x32\x2e\x36\x36\x36\x2d\x34\x32\x2e\x36\x36\x36\
+\x7a\x6d\x2d\x31\x39\x32\x20\x33\x34\x31\x2e\x33\x33\x68\x2d\x34\
+\x32\x2e\x36\x36\x37\x63\x2d\x31\x31\x2e\x37\x39\x37\x20\x30\x2d\
+\x32\x31\x2e\x33\x33\x33\x2d\x39\x2e\x35\x35\x37\x2d\x32\x31\x2e\
+\x33\x33\x33\x2d\x32\x31\x2e\x33\x33\x33\x73\x39\x2e\x35\x33\x36\
+\x2d\x32\x31\x2e\x33\x33\x33\x20\x32\x31\x2e\x33\x33\x33\x2d\x32\
+\x31\x2e\x33\x33\x33\x68\x34\x32\x2e\x36\x36\x37\x63\x31\x31\x2e\
+\x37\x39\x37\x20\x30\x20\x32\x31\x2e\x33\x33\x33\x20\x39\x2e\x35\
+\x35\x37\x20\x32\x31\x2e\x33\x33\x33\x20\x32\x31\x2e\x33\x33\x33\
+\x73\x2d\x39\x2e\x35\x33\x35\x20\x32\x31\x2e\x33\x33\x33\x2d\x32\
+\x31\x2e\x33\x33\x33\x20\x32\x31\x2e\x33\x33\x33\x7a\x6d\x31\x34\
+\x39\x2e\x33\x36\x2d\x31\x30\x36\x2e\x36\x37\x68\x2d\x33\x34\x31\
+\x2e\x33\x36\x76\x2d\x32\x31\x2e\x33\x33\x33\x68\x33\x34\x31\x2e\
+\x33\x33\x6c\x30\x2e\x30\x32\x32\x20\x32\x31\x2e\x33\x33\x33\x7a\
+\x6d\x2d\x32\x31\x33\x2e\x33\x36\x2d\x31\x34\x39\x2e\x33\x33\x63\
+\x30\x2d\x31\x31\x2e\x37\x37\x36\x20\x39\x2e\x35\x33\x36\x2d\x32\
+\x31\x2e\x33\x33\x33\x20\x32\x31\x2e\x33\x33\x33\x2d\x32\x31\x2e\
+\x33\x33\x33\x68\x34\x32\x2e\x36\x36\x37\x63\x31\x31\x2e\x37\x39\
+\x37\x20\x30\x20\x32\x31\x2e\x33\x33\x33\x20\x39\x2e\x35\x35\x37\
+\x20\x32\x31\x2e\x33\x33\x33\x20\x32\x31\x2e\x33\x33\x33\x73\x2d\
+\x39\x2e\x35\x33\x36\x20\x32\x31\x2e\x33\x33\x33\x2d\x32\x31\x2e\
+\x33\x33\x33\x20\x32\x31\x2e\x33\x33\x33\x68\x2d\x34\x32\x2e\x36\
+\x36\x37\x63\x2d\x31\x31\x2e\x37\x39\x37\x20\x31\x65\x2d\x33\x20\
+\x2d\x32\x31\x2e\x33\x33\x33\x2d\x39\x2e\x35\x35\x37\x2d\x32\x31\
+\x2e\x33\x33\x33\x2d\x32\x31\x2e\x33\x33\x33\x7a\x6d\x31\x39\x32\
+\x2d\x38\x35\x2e\x33\x33\x33\x68\x2d\x33\x32\x30\x76\x2d\x32\x31\
+\x2e\x33\x33\x33\x68\x33\x34\x31\x2e\x33\x33\x6c\x30\x2e\x30\x32\
+\x32\x20\x32\x31\x2e\x33\x33\x33\x68\x2d\x32\x31\x2e\x33\x35\x35\
+\x7a\x22\x2f\x3e\x0a\x09\x0a\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x01\x20\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x33\x32\
+\x20\x33\x32\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
+\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
+\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x32\x36\
+\x2e\x30\x30\x33\x31\x37\x37\x20\x32\x30\x2e\x30\x30\x30\x30\x30\
+\x31\x63\x31\x2e\x36\x30\x37\x34\x36\x36\x20\x36\x2e\x34\x32\x38\
+\x38\x2d\x33\x2e\x33\x37\x32\x38\x20\x31\x32\x2d\x31\x30\x2e\x30\
+\x30\x30\x30\x30\x31\x20\x31\x32\x2d\x36\x2e\x36\x32\x37\x31\x39\
+\x39\x39\x20\x30\x2d\x31\x31\x2e\x36\x32\x36\x36\x36\x36\x37\x2d\
+\x35\x2e\x34\x39\x32\x32\x36\x37\x2d\x31\x30\x2d\x31\x32\x20\x2e\
+\x39\x39\x39\x34\x36\x36\x37\x2d\x34\x20\x36\x2d\x31\x30\x2e\x30\
+\x30\x30\x30\x30\x31\x20\x31\x30\x2d\x32\x30\x2e\x30\x30\x30\x30\
+\x30\x31\x20\x34\x20\x39\x2e\x39\x39\x38\x39\x33\x33\x36\x20\x39\
+\x2e\x30\x30\x30\x35\x33\x34\x20\x31\x36\x2e\x30\x30\x30\x30\x30\
+\x31\x20\x31\x30\x2e\x30\x30\x30\x30\x30\x31\x20\x32\x30\x2e\x30\
+\x30\x30\x30\x30\x31\x7a\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x02\x7d\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x35\x31\
+\x32\x20\x35\x31\x32\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\
+\x30\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\
+\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\
+\x2f\x73\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\
+\x32\x31\x33\x2e\x33\x33\x33\x33\x33\x20\x30\x63\x31\x31\x37\x2e\
+\x38\x32\x31\x36\x36\x20\x30\x20\x32\x31\x33\x2e\x33\x33\x33\x33\
+\x34\x20\x39\x35\x2e\x35\x31\x31\x36\x38\x20\x32\x31\x33\x2e\x33\
+\x33\x33\x33\x34\x20\x32\x31\x33\x2e\x33\x33\x33\x33\x33\x20\x30\
+\x20\x31\x31\x37\x2e\x38\x32\x30\x33\x38\x2d\x39\x35\x2e\x35\x31\
+\x31\x36\x38\x20\x32\x31\x33\x2e\x33\x33\x33\x33\x34\x2d\x32\x31\
+\x33\x2e\x33\x33\x33\x33\x34\x20\x32\x31\x33\x2e\x33\x33\x33\x33\
+\x34\x2d\x31\x31\x37\x2e\x38\x32\x30\x33\x37\x20\x30\x2d\x32\x31\
+\x33\x2e\x33\x33\x33\x33\x33\x2d\x39\x35\x2e\x35\x31\x32\x39\x36\
+\x2d\x32\x31\x33\x2e\x33\x33\x33\x33\x33\x2d\x32\x31\x33\x2e\x33\
+\x33\x33\x33\x34\x20\x30\x2d\x31\x31\x37\x2e\x38\x32\x31\x36\x35\
+\x20\x39\x35\x2e\x35\x31\x32\x39\x36\x2d\x32\x31\x33\x2e\x33\x33\
+\x33\x33\x33\x20\x32\x31\x33\x2e\x33\x33\x33\x33\x33\x2d\x32\x31\
+\x33\x2e\x33\x33\x33\x33\x33\x7a\x6d\x32\x31\x2e\x33\x38\x30\x30\
+\x36\x20\x31\x39\x32\x68\x2d\x34\x32\x2e\x36\x36\x36\x36\x37\x76\
+\x31\x32\x38\x68\x34\x32\x2e\x36\x36\x36\x36\x37\x7a\x6d\x2d\x32\
+\x31\x2e\x31\x36\x33\x33\x31\x2d\x39\x30\x2e\x36\x36\x36\x36\x37\
+\x63\x2d\x31\x35\x2e\x35\x35\x33\x39\x32\x20\x30\x2d\x32\x36\x2e\
+\x38\x33\x36\x36\x39\x20\x31\x31\x2e\x32\x32\x30\x32\x37\x2d\x32\
+\x36\x2e\x38\x33\x36\x36\x39\x20\x32\x36\x2e\x33\x37\x30\x37\x38\
+\x20\x30\x20\x31\x35\x2e\x37\x36\x33\x34\x31\x20\x31\x30\x2e\x39\
+\x38\x35\x33\x38\x20\x32\x36\x2e\x39\x36\x32\x35\x36\x20\x32\x36\
+\x2e\x38\x33\x36\x36\x39\x20\x32\x36\x2e\x39\x36\x32\x35\x36\x20\
+\x31\x35\x2e\x32\x33\x34\x39\x39\x20\x30\x20\x32\x36\x2e\x34\x39\
+\x36\x36\x34\x2d\x31\x31\x2e\x31\x39\x39\x31\x35\x20\x32\x36\x2e\
+\x34\x39\x36\x36\x34\x2d\x32\x36\x2e\x36\x36\x36\x36\x37\x20\x30\
+\x2d\x31\x35\x2e\x34\x34\x36\x34\x2d\x31\x31\x2e\x32\x36\x31\x36\
+\x35\x2d\x32\x36\x2e\x36\x36\x36\x36\x37\x2d\x32\x36\x2e\x34\x39\
+\x36\x36\x34\x2d\x32\x36\x2e\x36\x36\x36\x36\x37\x7a\x22\x20\x66\
+\x69\x6c\x6c\x2d\x72\x75\x6c\x65\x3d\x22\x65\x76\x65\x6e\x6f\x64\
+\x64\x22\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x3d\x22\x6d\x61\
+\x74\x72\x69\x78\x28\x31\x2e\x32\x20\x30\x20\x30\x20\x31\x2e\x32\
+\x20\x2e\x30\x30\x30\x30\x30\x30\x34\x20\x2e\x30\x30\x30\x30\x30\
+\x30\x34\x29\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x09\xe0\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
+\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\
+\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\
+\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\
+\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\
+\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\
+\x38\x30\x30\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
+\x38\x30\x30\x22\x0a\x20\x20\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\
+\x22\x30\x20\x30\x20\x32\x31\x31\x2e\x36\x36\x36\x36\x36\x20\x32\
+\x31\x31\x2e\x36\x36\x36\x36\x37\x22\x0a\x20\x20\x20\x76\x65\x72\
+\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x0a\x20\x20\x20\x69\x64\
+\x3d\x22\x73\x76\x67\x31\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\
+\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x33\
+\x20\x28\x30\x65\x31\x35\x30\x65\x64\x36\x63\x34\x2c\x20\x32\x30\
+\x32\x33\x2d\x30\x37\x2d\x32\x31\x29\x22\x0a\x20\x20\x20\x78\x6d\
+\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\
+\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\
+\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x78\x6d\
+\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\
+\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\
+\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\
+\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\
+\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\
+\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\
+\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\
+\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
+\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
+\x22\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\
+\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\
+\x3d\x22\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x31\x22\x0a\x20\x20\
+\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\
+\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\
+\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x30\x30\x30\x30\x30\x30\
+\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\
+\x63\x69\x74\x79\x3d\x22\x30\x2e\x32\x35\x22\x0a\x20\x20\x20\x20\
+\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x73\x68\x6f\x77\x70\x61\
+\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\
+\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\
+\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\
+\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x63\
+\x68\x65\x63\x6b\x65\x72\x62\x6f\x61\x72\x64\x3d\x22\x30\x22\x0a\
+\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x65\
+\x73\x6b\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x64\x31\x64\x31\x64\x31\
+\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
+\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\
+\x6d\x6d\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x30\x2e\x35\x31\x32\x31\x33\x31\
+\x36\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x3a\x63\x78\x3d\x22\x34\x34\x37\x2e\x31\x35\x30\x36\x38\x22\
+\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\
+\x79\x3d\x22\x31\x39\x30\x2e\x33\x38\x30\x37\x35\x22\x0a\x20\x20\
+\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\
+\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\x32\x30\x22\x0a\
+\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\
+\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x30\x30\
+\x39\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\
+\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x2d\x38\x22\x0a\x20\
+\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\
+\x64\x6f\x77\x2d\x79\x3d\x22\x31\x39\x34\x22\x0a\x20\x20\x20\x20\
+\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\
+\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x0a\x20\
+\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\
+\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x6c\x61\x79\x65\
+\x72\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\
+\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\x31\x22\x20\x2f\
+\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
+\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\
+\x72\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\
+\x79\x65\x72\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\
+\x79\x65\x72\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\
+\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\
+\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\
+\x22\x66\x69\x6c\x6c\x3a\x23\x36\x36\x39\x39\x66\x66\x3b\x73\x74\
+\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x30\x2e\x33\x31\x34\
+\x37\x38\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x33\x20\x30\x20\x41\x20\x31\
+\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x31\x30\x35\x2e\x38\x33\x33\
+\x33\x32\x20\x30\x20\x30\x20\x30\x20\x30\x20\x31\x30\x35\x2e\x38\
+\x33\x33\x33\x33\x20\x41\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x30\x20\x30\x20\x30\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x33\x20\x32\x31\x31\x2e\x36\
+\x36\x36\x36\x37\x20\x41\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x30\x20\x30\x20\x30\
+\x20\x32\x31\x31\x2e\x36\x36\x36\x36\x37\x20\x31\x30\x35\x2e\x38\
+\x33\x33\x33\x33\x20\x41\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x30\x20\x30\x20\x30\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x33\x20\x30\x20\x7a\x20\x4d\
+\x20\x31\x30\x35\x2e\x37\x38\x36\x38\x32\x20\x34\x31\x2e\x36\x32\
+\x30\x31\x39\x39\x20\x43\x20\x31\x30\x39\x2e\x37\x39\x36\x33\x20\
+\x34\x31\x2e\x36\x32\x30\x31\x39\x39\x20\x31\x31\x33\x2e\x31\x38\
+\x39\x32\x33\x20\x34\x33\x2e\x30\x33\x38\x37\x39\x37\x20\x31\x31\
+\x35\x2e\x39\x36\x35\x30\x31\x20\x34\x35\x2e\x38\x37\x36\x32\x37\
+\x20\x43\x20\x31\x31\x38\x2e\x37\x34\x30\x38\x31\x20\x34\x38\x2e\
+\x36\x35\x32\x30\x35\x38\x20\x31\x32\x30\x2e\x31\x32\x38\x35\x38\
+\x20\x35\x32\x2e\x30\x31\x33\x36\x35\x35\x20\x31\x32\x30\x2e\x31\
+\x32\x38\x35\x38\x20\x35\x35\x2e\x39\x36\x31\x34\x34\x32\x20\x43\
+\x20\x31\x32\x30\x2e\x31\x32\x38\x35\x38\x20\x35\x39\x2e\x39\x30\
+\x39\x32\x33\x20\x31\x31\x38\x2e\x37\x30\x39\x39\x38\x20\x36\x33\
+\x2e\x32\x37\x31\x33\x34\x33\x20\x31\x31\x35\x2e\x38\x37\x32\x35\
+\x31\x20\x36\x36\x2e\x30\x34\x37\x31\x33\x31\x20\x43\x20\x31\x31\
+\x33\x2e\x30\x39\x36\x37\x32\x20\x36\x38\x2e\x38\x32\x32\x39\x32\
+\x20\x31\x30\x39\x2e\x37\x33\x34\x36\x31\x20\x37\x30\x2e\x32\x31\
+\x30\x37\x30\x31\x20\x31\x30\x35\x2e\x37\x38\x36\x38\x32\x20\x37\
+\x30\x2e\x32\x31\x30\x37\x30\x31\x20\x43\x20\x31\x30\x31\x2e\x38\
+\x33\x39\x30\x34\x20\x37\x30\x2e\x32\x31\x30\x37\x30\x31\x20\x39\
+\x38\x2e\x34\x37\x37\x34\x34\x20\x36\x38\x2e\x38\x32\x32\x39\x32\
+\x20\x39\x35\x2e\x37\x30\x31\x36\x35\x32\x20\x36\x36\x2e\x30\x34\
+\x37\x31\x33\x31\x20\x43\x20\x39\x32\x2e\x39\x32\x35\x38\x36\x33\
+\x20\x36\x33\x2e\x32\x37\x31\x33\x34\x33\x20\x39\x31\x2e\x35\x33\
+\x38\x30\x38\x32\x20\x35\x39\x2e\x39\x30\x39\x32\x33\x20\x39\x31\
+\x2e\x35\x33\x38\x30\x38\x32\x20\x35\x35\x2e\x39\x36\x31\x34\x34\
+\x32\x20\x43\x20\x39\x31\x2e\x35\x33\x38\x30\x38\x32\x20\x35\x32\
+\x2e\x30\x31\x33\x36\x35\x35\x20\x39\x32\x2e\x39\x32\x35\x38\x36\
+\x33\x20\x34\x38\x2e\x36\x35\x32\x30\x35\x38\x20\x39\x35\x2e\x37\
+\x30\x31\x36\x35\x32\x20\x34\x35\x2e\x38\x37\x36\x32\x37\x20\x43\
+\x20\x39\x38\x2e\x34\x37\x37\x34\x34\x20\x34\x33\x2e\x30\x33\x38\
+\x37\x39\x37\x20\x31\x30\x31\x2e\x38\x33\x39\x30\x34\x20\x34\x31\
+\x2e\x36\x32\x30\x31\x39\x39\x20\x31\x30\x35\x2e\x37\x38\x36\x38\
+\x32\x20\x34\x31\x2e\x36\x32\x30\x31\x39\x39\x20\x7a\x20\x4d\x20\
+\x38\x32\x2e\x34\x37\x30\x34\x31\x38\x20\x38\x33\x2e\x35\x33\x34\
+\x34\x33\x36\x20\x4c\x20\x31\x31\x38\x2e\x37\x34\x30\x35\x36\x20\
+\x38\x33\x2e\x35\x33\x34\x34\x33\x36\x20\x4c\x20\x31\x31\x38\x2e\
+\x37\x34\x30\x35\x36\x20\x31\x35\x32\x2e\x30\x39\x36\x36\x36\x20\
+\x43\x20\x31\x31\x38\x2e\x37\x34\x30\x35\x36\x20\x31\x35\x38\x2e\
+\x32\x30\x33\x33\x39\x20\x31\x31\x39\x2e\x34\x35\x30\x33\x38\x20\
+\x31\x36\x32\x2e\x31\x32\x30\x32\x31\x20\x31\x32\x30\x2e\x38\x36\
+\x39\x31\x31\x20\x31\x36\x33\x2e\x38\x34\x37\x33\x36\x20\x43\x20\
+\x31\x32\x32\x2e\x32\x38\x37\x38\x35\x20\x31\x36\x35\x2e\x35\x31\
+\x32\x38\x34\x20\x31\x32\x35\x2e\x30\x36\x33\x34\x31\x20\x31\x36\
+\x36\x2e\x34\x36\x39\x31\x39\x20\x31\x32\x39\x2e\x31\x39\x36\x32\
+\x35\x20\x31\x36\x36\x2e\x37\x31\x35\x39\x32\x20\x4c\x20\x31\x32\
+\x39\x2e\x31\x39\x36\x32\x35\x20\x31\x37\x30\x2e\x30\x34\x36\x34\
+\x37\x20\x4c\x20\x38\x32\x2e\x34\x37\x30\x34\x31\x38\x20\x31\x37\
+\x30\x2e\x30\x34\x36\x34\x37\x20\x4c\x20\x38\x32\x2e\x34\x37\x30\
+\x34\x31\x38\x20\x31\x36\x36\x2e\x37\x31\x35\x39\x32\x20\x43\x20\
+\x38\x36\x2e\x32\x39\x34\x38\x33\x38\x20\x31\x36\x36\x2e\x35\x39\
+\x32\x35\x36\x20\x38\x39\x2e\x31\x33\x32\x35\x35\x32\x20\x31\x36\
+\x35\x2e\x34\x38\x32\x31\x32\x20\x39\x30\x2e\x39\x38\x33\x30\x37\
+\x37\x20\x31\x36\x33\x2e\x33\x38\x34\x38\x36\x20\x43\x20\x39\x32\
+\x2e\x32\x31\x36\x37\x36\x20\x31\x36\x31\x2e\x39\x36\x36\x31\x33\
+\x20\x39\x32\x2e\x38\x33\x33\x36\x31\x20\x31\x35\x38\x2e\x32\x30\
+\x33\x33\x39\x20\x39\x32\x2e\x38\x33\x33\x36\x31\x20\x31\x35\x32\
+\x2e\x30\x39\x36\x36\x36\x20\x4c\x20\x39\x32\x2e\x38\x33\x33\x36\
+\x31\x20\x31\x30\x31\x2e\x35\x37\x37\x32\x36\x20\x43\x20\x39\x32\
+\x2e\x38\x33\x33\x36\x31\x20\x39\x35\x2e\x34\x37\x30\x35\x32\x36\
+\x20\x39\x32\x2e\x31\x32\x33\x37\x39\x34\x20\x39\x31\x2e\x35\x38\
+\x34\x30\x31\x35\x20\x39\x30\x2e\x37\x30\x35\x30\x35\x38\x20\x38\
+\x39\x2e\x39\x31\x38\x35\x34\x32\x20\x43\x20\x38\x39\x2e\x32\x38\
+\x36\x33\x32\x31\x20\x38\x38\x2e\x31\x39\x31\x33\x38\x36\x20\x38\
+\x36\x2e\x35\x34\x31\x35\x37\x34\x20\x38\x37\x2e\x32\x30\x34\x37\
+\x33\x36\x20\x38\x32\x2e\x34\x37\x30\x34\x31\x38\x20\x38\x36\x2e\
+\x39\x35\x38\x20\x4c\x20\x38\x32\x2e\x34\x37\x30\x34\x31\x38\x20\
+\x38\x33\x2e\x35\x33\x34\x34\x33\x36\x20\x7a\x20\x22\x20\x2f\x3e\
+\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x08\x98\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x20\x73\x74\x61\x6e\x64\x61\x6c\x6f\x6e\x65\x3d\x22\
+\x6e\x6f\x22\x3f\x3e\x0a\x3c\x21\x2d\x2d\x20\x43\x72\x65\x61\x74\
+\x65\x64\x20\x77\x69\x74\x68\x20\x49\x6e\x6b\x73\x63\x61\x70\x65\
+\x20\x28\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\
+\x73\x63\x61\x70\x65\x2e\x6f\x72\x67\x2f\x29\x20\x2d\x2d\x3e\x0a\
+\x0a\x3c\x73\x76\x67\x0a\x20\x20\x20\x77\x69\x64\x74\x68\x3d\x22\
+\x38\x30\x30\x22\x0a\x20\x20\x20\x68\x65\x69\x67\x68\x74\x3d\x22\
+\x38\x30\x30\x22\x0a\x20\x20\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\
+\x22\x30\x20\x30\x20\x32\x31\x31\x2e\x36\x36\x36\x36\x36\x20\x32\
+\x31\x31\x2e\x36\x36\x36\x36\x37\x22\x0a\x20\x20\x20\x76\x65\x72\
+\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\x22\x0a\x20\x20\x20\x69\x64\
+\x3d\x22\x73\x76\x67\x31\x22\x0a\x20\x20\x20\x69\x6e\x6b\x73\x63\
+\x61\x70\x65\x3a\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x33\
+\x20\x28\x30\x65\x31\x35\x30\x65\x64\x36\x63\x34\x2c\x20\x32\x30\
+\x32\x33\x2d\x30\x37\x2d\x32\x31\x29\x22\x0a\x20\x20\x20\x78\x6d\
+\x6c\x6e\x73\x3a\x69\x6e\x6b\x73\x63\x61\x70\x65\x3d\x22\x68\x74\
+\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x2e\x6f\x72\x67\x2f\x6e\x61\x6d\x65\x73\x70\x61\x63\x65\x73\
+\x2f\x69\x6e\x6b\x73\x63\x61\x70\x65\x22\x0a\x20\x20\x20\x78\x6d\
+\x6c\x6e\x73\x3a\x73\x6f\x64\x69\x70\x6f\x64\x69\x3d\x22\x68\x74\
+\x74\x70\x3a\x2f\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2e\x73\x6f\
+\x75\x72\x63\x65\x66\x6f\x72\x67\x65\x2e\x6e\x65\x74\x2f\x44\x54\
+\x44\x2f\x73\x6f\x64\x69\x70\x6f\x64\x69\x2d\x30\x2e\x64\x74\x64\
+\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\
+\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\
+\x30\x30\x2f\x73\x76\x67\x22\x0a\x20\x20\x20\x78\x6d\x6c\x6e\x73\
+\x3a\x73\x76\x67\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\
+\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\x76\x67\
+\x22\x3e\x0a\x20\x20\x3c\x73\x6f\x64\x69\x70\x6f\x64\x69\x3a\x6e\
+\x61\x6d\x65\x64\x76\x69\x65\x77\x0a\x20\x20\x20\x20\x20\x69\x64\
+\x3d\x22\x6e\x61\x6d\x65\x64\x76\x69\x65\x77\x31\x22\x0a\x20\x20\
+\x20\x20\x20\x70\x61\x67\x65\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x66\
+\x66\x66\x66\x66\x66\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\
+\x65\x72\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x30\x30\x30\x30\x30\x30\
+\x22\x0a\x20\x20\x20\x20\x20\x62\x6f\x72\x64\x65\x72\x6f\x70\x61\
+\x63\x69\x74\x79\x3d\x22\x30\x2e\x32\x35\x22\x0a\x20\x20\x20\x20\
+\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x73\x68\x6f\x77\x70\x61\
+\x67\x65\x73\x68\x61\x64\x6f\x77\x3d\x22\x32\x22\x0a\x20\x20\x20\
+\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x6f\
+\x70\x61\x63\x69\x74\x79\x3d\x22\x30\x2e\x30\x22\x0a\x20\x20\x20\
+\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x70\x61\x67\x65\x63\
+\x68\x65\x63\x6b\x65\x72\x62\x6f\x61\x72\x64\x3d\x22\x30\x22\x0a\
+\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x64\x65\
+\x73\x6b\x63\x6f\x6c\x6f\x72\x3d\x22\x23\x64\x31\x64\x31\x64\x31\
+\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\
+\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2d\x75\x6e\x69\x74\x73\x3d\x22\
+\x6d\x6d\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x3a\x7a\x6f\x6f\x6d\x3d\x22\x30\x2e\x35\x31\x32\x31\x33\x31\
+\x36\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\
+\x65\x3a\x63\x78\x3d\x22\x34\x34\x37\x2e\x31\x35\x30\x36\x38\x22\
+\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\
+\x79\x3d\x22\x31\x35\x33\x2e\x32\x38\x30\x39\x31\x22\x0a\x20\x20\
+\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\
+\x6f\x77\x2d\x77\x69\x64\x74\x68\x3d\x22\x31\x39\x32\x30\x22\x0a\
+\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\
+\x6e\x64\x6f\x77\x2d\x68\x65\x69\x67\x68\x74\x3d\x22\x31\x30\x30\
+\x39\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\
+\x3a\x77\x69\x6e\x64\x6f\x77\x2d\x78\x3d\x22\x2d\x38\x22\x0a\x20\
+\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\
+\x64\x6f\x77\x2d\x79\x3d\x22\x31\x39\x34\x22\x0a\x20\x20\x20\x20\
+\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x77\x69\x6e\x64\x6f\x77\
+\x2d\x6d\x61\x78\x69\x6d\x69\x7a\x65\x64\x3d\x22\x31\x22\x0a\x20\
+\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\x70\x65\x3a\x63\x75\x72\
+\x72\x65\x6e\x74\x2d\x6c\x61\x79\x65\x72\x3d\x22\x6c\x61\x79\x65\
+\x72\x31\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x64\x65\x66\x73\x0a\x20\
+\x20\x20\x20\x20\x69\x64\x3d\x22\x64\x65\x66\x73\x31\x22\x20\x2f\
+\x3e\x0a\x20\x20\x3c\x67\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\
+\x63\x61\x70\x65\x3a\x6c\x61\x62\x65\x6c\x3d\x22\x4c\x61\x79\x65\
+\x72\x20\x31\x22\x0a\x20\x20\x20\x20\x20\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x3a\x67\x72\x6f\x75\x70\x6d\x6f\x64\x65\x3d\x22\x6c\x61\
+\x79\x65\x72\x22\x0a\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x6c\x61\
+\x79\x65\x72\x31\x22\x3e\x0a\x20\x20\x20\x20\x3c\x70\x61\x74\x68\
+\x0a\x20\x20\x20\x20\x20\x20\x20\x69\x64\x3d\x22\x70\x61\x74\x68\
+\x31\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x73\x74\x79\x6c\x65\x3d\
+\x22\x66\x69\x6c\x6c\x3a\x23\x30\x30\x63\x63\x30\x30\x3b\x73\x74\
+\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3a\x30\x2e\x33\x31\x34\
+\x37\x38\x38\x22\x0a\x20\x20\x20\x20\x20\x20\x20\x64\x3d\x22\x4d\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x33\x20\x30\x20\x41\x20\x31\
+\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x31\x30\x35\x2e\x38\x33\x33\
+\x33\x32\x20\x30\x20\x30\x20\x30\x20\x30\x20\x31\x30\x35\x2e\x38\
+\x33\x33\x33\x33\x20\x41\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x30\x20\x30\x20\x30\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x33\x20\x32\x31\x31\x2e\x36\
+\x36\x36\x36\x37\x20\x41\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x30\x20\x30\x20\x30\
+\x20\x32\x31\x31\x2e\x36\x36\x36\x36\x37\x20\x31\x30\x35\x2e\x38\
+\x33\x33\x33\x33\x20\x41\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\
+\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\x30\x20\x30\x20\x30\
+\x20\x31\x38\x38\x2e\x36\x35\x36\x31\x38\x20\x33\x39\x2e\x39\x39\
+\x30\x33\x32\x34\x20\x43\x20\x31\x37\x35\x2e\x38\x33\x33\x39\x32\
+\x20\x35\x32\x2e\x30\x35\x36\x39\x31\x35\x20\x31\x36\x32\x2e\x31\
+\x31\x32\x32\x31\x20\x36\x37\x2e\x33\x38\x33\x38\x34\x33\x20\x31\
+\x34\x37\x2e\x34\x34\x35\x32\x36\x20\x38\x36\x2e\x31\x33\x37\x33\
+\x37\x38\x20\x43\x20\x31\x32\x36\x2e\x30\x38\x30\x34\x33\x20\x31\
+\x31\x33\x2e\x34\x35\x35\x30\x31\x20\x31\x30\x39\x2e\x37\x37\x31\
+\x32\x35\x20\x31\x33\x38\x2e\x39\x37\x38\x37\x37\x20\x39\x38\x2e\
+\x35\x31\x38\x30\x31\x38\x20\x31\x36\x32\x2e\x37\x30\x38\x34\x31\
+\x20\x4c\x20\x38\x39\x2e\x34\x36\x36\x38\x39\x20\x31\x36\x38\x2e\
+\x38\x32\x34\x33\x32\x20\x43\x20\x38\x31\x2e\x39\x36\x34\x37\x33\
+\x35\x20\x31\x37\x34\x2e\x30\x34\x33\x32\x31\x20\x37\x36\x2e\x38\
+\x36\x37\x38\x35\x38\x20\x31\x37\x37\x2e\x39\x31\x36\x33\x38\x20\
+\x37\x34\x2e\x31\x37\x36\x38\x36\x38\x20\x31\x38\x30\x2e\x34\x34\
+\x34\x32\x38\x20\x43\x20\x37\x33\x2e\x31\x31\x36\x37\x38\x20\x31\
+\x37\x36\x2e\x36\x31\x31\x36\x36\x20\x37\x30\x2e\x37\x39\x32\x36\
+\x37\x31\x20\x31\x37\x30\x2e\x33\x33\x33\x30\x34\x20\x36\x37\x2e\
+\x32\x30\x34\x36\x38\x33\x20\x31\x36\x31\x2e\x36\x30\x37\x37\x31\
+\x20\x4c\x20\x36\x33\x2e\x37\x38\x30\x30\x38\x36\x20\x31\x35\x33\
+\x2e\x36\x35\x36\x37\x37\x20\x43\x20\x35\x38\x2e\x38\x38\x37\x33\
+\x37\x36\x20\x31\x34\x32\x2e\x32\x34\x30\x34\x35\x20\x35\x34\x2e\
+\x33\x32\x30\x34\x39\x36\x20\x31\x33\x33\x2e\x38\x30\x30\x34\x20\
+\x35\x30\x2e\x30\x38\x30\x31\x34\x37\x20\x31\x32\x38\x2e\x33\x33\
+\x36\x38\x37\x20\x43\x20\x34\x35\x2e\x39\x32\x31\x33\x34\x33\x20\
+\x31\x32\x32\x2e\x38\x37\x33\x33\x34\x20\x34\x31\x2e\x32\x33\x32\
+\x37\x31\x33\x20\x31\x31\x39\x2e\x32\x34\x34\x37\x20\x33\x36\x2e\
+\x30\x31\x33\x38\x32\x32\x20\x31\x31\x37\x2e\x34\x35\x30\x37\x31\
+\x20\x43\x20\x34\x34\x2e\x38\x32\x30\x37\x20\x31\x30\x38\x2e\x31\
+\x35\x34\x35\x36\x20\x35\x32\x2e\x38\x39\x33\x34\x33\x34\x20\x31\
+\x30\x33\x2e\x35\x30\x36\x33\x34\x20\x36\x30\x2e\x32\x33\x32\x34\
+\x39\x39\x20\x31\x30\x33\x2e\x35\x30\x36\x33\x34\x20\x43\x20\x36\
+\x36\x2e\x35\x31\x31\x34\x37\x37\x20\x31\x30\x33\x2e\x35\x30\x36\
+\x33\x34\x20\x37\x33\x2e\x34\x38\x33\x38\x30\x36\x20\x31\x31\x32\
+\x2e\x30\x32\x38\x32\x35\x20\x38\x31\x2e\x31\x34\x39\x30\x35\x32\
+\x20\x31\x32\x39\x2e\x30\x37\x31\x31\x39\x20\x4c\x20\x38\x34\x2e\
+\x39\x34\x31\x30\x36\x39\x20\x31\x33\x37\x2e\x36\x33\x33\x34\x36\
+\x20\x43\x20\x39\x38\x2e\x37\x32\x32\x32\x20\x31\x31\x34\x2e\x33\
+\x39\x33\x30\x39\x20\x31\x31\x36\x2e\x34\x31\x37\x32\x35\x20\x39\
+\x31\x2e\x38\x30\x34\x37\x37\x33\x20\x31\x33\x38\x2e\x30\x32\x36\
+\x37\x32\x20\x36\x39\x2e\x38\x36\x39\x31\x32\x20\x43\x20\x31\x35\
+\x32\x2e\x38\x31\x30\x31\x36\x20\x35\x34\x2e\x38\x36\x32\x35\x33\
+\x31\x20\x31\x36\x37\x2e\x33\x35\x39\x30\x35\x20\x34\x32\x2e\x33\
+\x30\x30\x37\x31\x39\x20\x31\x38\x31\x2e\x36\x38\x34\x35\x32\x20\
+\x33\x32\x2e\x30\x36\x34\x37\x30\x39\x20\x41\x20\x31\x30\x35\x2e\
+\x38\x33\x33\x33\x32\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x32\x20\
+\x30\x20\x30\x20\x30\x20\x31\x30\x35\x2e\x38\x33\x33\x33\x33\x20\
+\x30\x20\x7a\x20\x22\x20\x2f\x3e\x0a\x20\x20\x3c\x2f\x67\x3e\x0a\
+\x3c\x2f\x73\x76\x67\x3e\x0a\
+\x00\x00\x06\xd0\
+\x3c\
+\x73\x76\x67\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x38\x30\x30\x22\
+\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x31\x36\
+\x20\x31\x36\x22\x20\x77\x69\x64\x74\x68\x3d\x22\x38\x30\x30\x22\
+\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\
+\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\x30\x30\x30\x2f\x73\
+\x76\x67\x22\x3e\x3c\x70\x61\x74\x68\x20\x64\x3d\x22\x6d\x31\x36\
+\x20\x37\x2e\x33\x33\x38\x39\x38\x31\x38\x61\x37\x2e\x38\x32\x20\
+\x38\x2e\x33\x33\x37\x33\x36\x35\x31\x20\x30\x20\x30\x20\x30\x20\
+\x2d\x38\x2d\x37\x2e\x33\x33\x35\x31\x37\x35\x34\x39\x20\x37\x2e\
+\x38\x32\x20\x38\x2e\x33\x33\x37\x33\x36\x35\x31\x20\x30\x20\x30\
+\x20\x30\x20\x2d\x38\x20\x37\x2e\x33\x33\x35\x31\x37\x35\x34\x39\
+\x76\x31\x2e\x33\x32\x32\x30\x33\x37\x34\x61\x37\x2e\x38\x32\x20\
+\x38\x2e\x33\x33\x37\x33\x36\x35\x31\x20\x30\x20\x30\x20\x30\x20\
+\x38\x20\x37\x2e\x33\x33\x35\x31\x37\x34\x38\x20\x37\x2e\x38\x32\
+\x20\x38\x2e\x33\x33\x37\x33\x36\x35\x31\x20\x30\x20\x30\x20\x30\
+\x20\x38\x2d\x37\x2e\x33\x33\x35\x31\x37\x34\x38\x7a\x6d\x2d\x31\
+\x2e\x32\x35\x20\x30\x68\x2d\x33\x61\x31\x31\x2e\x33\x34\x20\x31\
+\x32\x2e\x30\x39\x30\x32\x34\x36\x20\x30\x20\x30\x20\x30\x20\x2d\
+\x2e\x34\x33\x2d\x32\x2e\x37\x30\x38\x30\x34\x34\x34\x20\x37\x2e\
+\x36\x20\x38\x2e\x31\x30\x32\x38\x31\x30\x31\x20\x30\x20\x30\x20\
+\x30\x20\x31\x2e\x37\x35\x2d\x31\x2e\x30\x36\x36\x31\x35\x39\x33\
+\x20\x36\x20\x36\x2e\x33\x39\x36\x39\x35\x35\x33\x20\x30\x20\x30\
+\x20\x31\x20\x31\x2e\x36\x35\x20\x33\x2e\x37\x37\x34\x32\x30\x33\
+\x37\x7a\x6d\x2d\x39\x2e\x31\x38\x20\x30\x61\x39\x2e\x36\x39\x20\
+\x31\x30\x2e\x33\x33\x31\x30\x38\x33\x20\x30\x20\x30\x20\x31\x20\
+\x2e\x33\x37\x2d\x32\x2e\x32\x38\x31\x35\x38\x30\x38\x20\x38\x2e\
+\x34\x33\x20\x38\x2e\x39\x38\x37\x37\x32\x32\x32\x20\x30\x20\x30\
+\x20\x30\x20\x32\x2e\x30\x36\x2e\x32\x37\x37\x32\x30\x31\x34\x20\
+\x38\x2e\x34\x39\x20\x39\x2e\x30\x35\x31\x36\x39\x31\x38\x20\x30\
+\x20\x30\x20\x30\x20\x32\x2e\x30\x39\x2d\x2e\x32\x37\x37\x32\x30\
+\x31\x34\x20\x31\x30\x2e\x32\x20\x31\x30\x2e\x38\x37\x34\x38\x32\
+\x34\x20\x30\x20\x30\x20\x31\x20\x2e\x33\x37\x20\x32\x2e\x32\x38\
+\x31\x35\x38\x30\x38\x7a\x6d\x34\x2e\x39\x32\x20\x31\x2e\x33\x32\
+\x32\x30\x33\x37\x34\x61\x39\x2e\x35\x39\x20\x31\x30\x2e\x32\x32\
+\x34\x34\x36\x37\x20\x30\x20\x30\x20\x31\x20\x2d\x2e\x33\x37\x20\
+\x32\x2e\x32\x38\x31\x35\x38\x30\x38\x20\x38\x2e\x35\x33\x20\x39\
+\x2e\x30\x39\x34\x33\x33\x38\x32\x20\x30\x20\x30\x20\x30\x20\x2d\
+\x34\x2e\x31\x38\x20\x30\x20\x39\x2e\x36\x39\x20\x31\x30\x2e\x33\
+\x33\x31\x30\x38\x33\x20\x30\x20\x30\x20\x31\x20\x2d\x2e\x33\x37\
+\x2d\x32\x2e\x32\x38\x31\x35\x38\x30\x38\x7a\x6d\x2e\x34\x2d\x35\
+\x2e\x33\x33\x30\x37\x39\x36\x31\x61\x31\x31\x2e\x38\x32\x20\x31\
+\x32\x2e\x36\x30\x32\x30\x30\x32\x20\x30\x20\x30\x20\x30\x20\x2d\
+\x2e\x38\x39\x2d\x31\x2e\x37\x32\x37\x31\x37\x38\x20\x36\x2e\x38\
+\x39\x20\x37\x2e\x33\x34\x35\x38\x33\x37\x20\x30\x20\x30\x20\x31\
+\x20\x32\x20\x31\x2e\x30\x36\x36\x31\x35\x39\x33\x20\x36\x2e\x35\
+\x37\x20\x37\x2e\x30\x30\x34\x36\x36\x36\x31\x20\x30\x20\x30\x20\
+\x31\x20\x2d\x31\x2e\x31\x34\x2e\x37\x30\x33\x36\x36\x35\x7a\x6d\
+\x2d\x32\x2e\x36\x2d\x31\x2e\x39\x38\x33\x30\x35\x36\x32\x61\x31\
+\x30\x20\x31\x30\x2e\x36\x36\x31\x35\x39\x32\x20\x30\x20\x30\x20\
+\x31\x20\x31\x2e\x33\x38\x20\x32\x2e\x34\x35\x32\x31\x36\x36\x33\
+\x20\x37\x2e\x36\x33\x20\x38\x2e\x31\x33\x34\x37\x39\x34\x38\x20\
+\x30\x20\x30\x20\x31\x20\x2d\x31\x2e\x36\x37\x2e\x32\x30\x32\x35\
+\x37\x30\x32\x20\x37\x2e\x35\x36\x20\x38\x2e\x30\x36\x30\x31\x36\
+\x33\x37\x20\x30\x20\x30\x20\x31\x20\x2d\x31\x2e\x36\x37\x2d\x2e\
+\x32\x30\x32\x35\x37\x30\x32\x20\x39\x2e\x38\x32\x20\x31\x30\x2e\
+\x34\x36\x39\x36\x38\x34\x20\x30\x20\x30\x20\x31\x20\x31\x2e\x33\
+\x38\x2d\x32\x2e\x34\x35\x32\x31\x36\x36\x33\x7a\x6d\x2d\x33\x2e\
+\x31\x35\x20\x32\x2e\x30\x32\x35\x37\x30\x32\x35\x61\x36\x2e\x35\
+\x37\x20\x37\x2e\x30\x30\x34\x36\x36\x36\x31\x20\x30\x20\x30\x20\
+\x31\x20\x2d\x31\x2e\x31\x34\x2d\x2e\x37\x30\x33\x36\x36\x35\x20\
+\x36\x2e\x38\x39\x20\x37\x2e\x33\x34\x35\x38\x33\x37\x20\x30\x20\
+\x30\x20\x31\x20\x32\x2d\x31\x2e\x30\x36\x36\x31\x35\x39\x33\x20\
+\x31\x30\x2e\x33\x38\x20\x31\x31\x2e\x30\x36\x36\x37\x33\x32\x20\
+\x30\x20\x30\x20\x30\x20\x2d\x2e\x38\x36\x20\x31\x2e\x37\x36\x39\
+\x38\x32\x34\x33\x7a\x6d\x2d\x32\x2e\x31\x34\x2e\x31\x38\x31\x32\
+\x34\x37\x31\x61\x37\x2e\x36\x20\x38\x2e\x31\x30\x32\x38\x31\x30\
+\x31\x20\x30\x20\x30\x20\x30\x20\x31\x2e\x37\x35\x20\x31\x2e\x30\
+\x36\x36\x31\x35\x39\x33\x20\x31\x31\x20\x31\x31\x2e\x37\x32\x37\
+\x37\x35\x32\x20\x30\x20\x30\x20\x30\x20\x2d\x2e\x34\x33\x20\x32\
+\x2e\x37\x30\x38\x30\x34\x34\x34\x68\x2d\x33\x61\x36\x20\x36\x2e\
+\x33\x39\x36\x39\x35\x35\x33\x20\x30\x20\x30\x20\x31\x20\x31\x2e\
+\x36\x38\x2d\x33\x2e\x37\x37\x34\x32\x30\x33\x37\x7a\x6d\x2d\x31\
+\x2e\x37\x32\x20\x35\x2e\x31\x30\x36\x39\x30\x32\x37\x68\x33\x61\
+\x31\x31\x20\x31\x31\x2e\x37\x32\x37\x37\x35\x32\x20\x30\x20\x30\
+\x20\x30\x20\x2e\x34\x33\x20\x32\x2e\x37\x30\x38\x30\x34\x34\x38\
+\x20\x37\x2e\x36\x20\x38\x2e\x31\x30\x32\x38\x31\x30\x31\x20\x30\
+\x20\x30\x20\x30\x20\x2d\x31\x2e\x37\x35\x20\x31\x2e\x30\x36\x36\
+\x31\x35\x38\x20\x36\x20\x36\x2e\x33\x39\x36\x39\x35\x35\x33\x20\
+\x30\x20\x30\x20\x31\x20\x2d\x31\x2e\x36\x38\x2d\x33\x2e\x37\x37\
+\x34\x32\x30\x32\x38\x7a\x6d\x33\x2e\x38\x36\x20\x33\x2e\x39\x36\
+\x36\x31\x31\x32\x38\x61\x31\x30\x2e\x33\x38\x20\x31\x31\x2e\x30\
+\x36\x36\x37\x33\x32\x20\x30\x20\x30\x20\x30\x20\x2e\x38\x36\x20\
+\x31\x2e\x37\x36\x39\x38\x32\x34\x20\x36\x2e\x38\x39\x20\x37\x2e\
+\x33\x34\x35\x38\x33\x37\x20\x30\x20\x30\x20\x31\x20\x2d\x32\x2d\
+\x31\x2e\x30\x36\x36\x31\x36\x20\x36\x2e\x35\x37\x20\x37\x2e\x30\
+\x30\x34\x36\x36\x36\x31\x20\x30\x20\x30\x20\x31\x20\x31\x2e\x31\
+\x34\x2d\x2e\x37\x30\x33\x36\x36\x34\x7a\x6d\x32\x2e\x35\x37\x20\
+\x32\x2e\x30\x32\x35\x37\x30\x32\x61\x39\x2e\x38\x32\x20\x31\x30\
+\x2e\x34\x36\x39\x36\x38\x34\x20\x30\x20\x30\x20\x31\x20\x2d\x31\
+\x2e\x33\x38\x2d\x32\x2e\x34\x35\x32\x31\x36\x36\x20\x37\x2e\x34\
+\x33\x20\x37\x2e\x39\x32\x31\x35\x36\x33\x20\x30\x20\x30\x20\x31\
+\x20\x33\x2e\x33\x34\x20\x30\x20\x39\x2e\x37\x36\x20\x31\x30\x2e\
+\x34\x30\x35\x37\x31\x34\x20\x30\x20\x30\x20\x31\x20\x2d\x31\x2e\
+\x33\x38\x20\x32\x2e\x34\x35\x32\x31\x36\x36\x7a\x6d\x33\x2e\x31\
+\x35\x2d\x32\x2e\x30\x32\x35\x37\x30\x32\x61\x36\x2e\x35\x37\x20\
+\x37\x2e\x30\x30\x34\x36\x36\x36\x31\x20\x30\x20\x30\x20\x31\x20\
+\x31\x2e\x31\x39\x2e\x37\x30\x33\x36\x36\x34\x20\x37\x2e\x32\x34\
+\x20\x37\x2e\x37\x31\x38\x39\x39\x32\x38\x20\x30\x20\x30\x20\x31\
+\x20\x2d\x32\x20\x31\x2e\x30\x36\x36\x31\x36\x20\x31\x31\x2e\x34\
+\x38\x20\x31\x32\x2e\x32\x33\x39\x35\x30\x38\x20\x30\x20\x30\x20\
+\x30\x20\x2e\x38\x31\x2d\x31\x2e\x37\x36\x39\x38\x32\x34\x7a\x6d\
+\x32\x2e\x31\x34\x2d\x2e\x31\x38\x31\x32\x34\x38\x61\x37\x2e\x36\
+\x20\x38\x2e\x31\x30\x32\x38\x31\x30\x31\x20\x30\x20\x30\x20\x30\
+\x20\x2d\x31\x2e\x37\x35\x2d\x31\x2e\x30\x36\x36\x31\x35\x38\x20\
+\x31\x30\x2e\x38\x20\x31\x31\x2e\x35\x31\x34\x35\x32\x20\x30\x20\
+\x30\x20\x30\x20\x2e\x34\x33\x2d\x32\x2e\x37\x30\x38\x30\x34\x35\
+\x32\x68\x33\x61\x36\x20\x36\x2e\x33\x39\x36\x39\x35\x35\x33\x20\
+\x30\x20\x30\x20\x31\x20\x2d\x31\x2e\x36\x38\x20\x33\x2e\x37\x37\
+\x34\x32\x30\x33\x32\x7a\x22\x2f\x3e\x3c\x2f\x73\x76\x67\x3e\
+\x00\x00\x04\x5b\
+\x3c\
+\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\
+\x30\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x55\x54\x46\
+\x2d\x38\x22\x3f\x3e\x0a\x3c\x73\x76\x67\x20\x77\x69\x64\x74\x68\
+\x3d\x22\x38\x30\x30\x70\x78\x22\x20\x68\x65\x69\x67\x68\x74\x3d\
+\x22\x38\x30\x30\x70\x78\x22\x20\x66\x69\x6c\x6c\x3d\x22\x6e\x6f\
+\x6e\x65\x22\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x31\
+\x22\x20\x76\x69\x65\x77\x42\x6f\x78\x3d\x22\x30\x20\x30\x20\x32\
+\x34\x20\x32\x34\x22\x20\x78\x6d\x6c\x6e\x73\x3d\x22\x68\x74\x74\
+\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x77\x33\x2e\x6f\x72\x67\x2f\x32\
+\x30\x30\x30\x2f\x73\x76\x67\x22\x3e\x0a\x20\x3c\x70\x61\x74\x68\
+\x20\x64\x3d\x22\x6d\x37\x2e\x30\x38\x36\x31\x20\x33\x2e\x34\x34\
+\x34\x34\x63\x2d\x31\x2e\x32\x31\x34\x32\x20\x39\x2e\x34\x31\x65\
+\x2d\x34\x20\x2d\x31\x2e\x38\x35\x30\x36\x20\x30\x2e\x30\x31\x36\
+\x32\x39\x31\x2d\x32\x2e\x33\x34\x33\x39\x20\x30\x2e\x32\x36\x36\
+\x33\x34\x2d\x30\x2e\x34\x36\x32\x33\x31\x20\x30\x2e\x32\x33\x34\
+\x33\x33\x2d\x30\x2e\x38\x33\x38\x31\x37\x20\x30\x2e\x36\x30\x38\
+\x32\x34\x2d\x31\x2e\x30\x37\x33\x37\x20\x31\x2e\x30\x36\x38\x32\
+\x2d\x30\x2e\x32\x36\x37\x37\x39\x20\x30\x2e\x35\x32\x32\x38\x34\
+\x2d\x30\x2e\x32\x36\x37\x37\x39\x20\x31\x2e\x32\x30\x37\x33\x2d\
+\x30\x2e\x32\x36\x37\x37\x39\x20\x32\x2e\x35\x37\x36\x32\x76\x31\
+\x31\x2e\x37\x33\x32\x63\x30\x20\x31\x2e\x33\x36\x38\x39\x20\x30\
+\x20\x32\x2e\x30\x35\x33\x34\x20\x30\x2e\x32\x36\x37\x37\x39\x20\
+\x32\x2e\x35\x37\x36\x32\x20\x30\x2e\x32\x33\x35\x35\x35\x20\x30\
+\x2e\x34\x35\x39\x38\x38\x20\x30\x2e\x36\x31\x31\x34\x31\x20\x30\
+\x2e\x38\x33\x33\x38\x34\x20\x31\x2e\x30\x37\x33\x37\x20\x31\x2e\
+\x30\x36\x38\x31\x20\x30\x2e\x35\x32\x35\x35\x36\x20\x30\x2e\x32\
+\x36\x36\x34\x32\x20\x31\x2e\x32\x31\x33\x36\x20\x30\x2e\x32\x36\
+\x36\x34\x32\x20\x32\x2e\x35\x38\x39\x36\x20\x30\x2e\x32\x36\x36\
+\x34\x32\x68\x39\x2e\x33\x33\x36\x34\x63\x31\x2e\x33\x37\x36\x20\
+\x30\x20\x32\x2e\x30\x36\x34\x31\x20\x30\x20\x32\x2e\x35\x38\x39\
+\x36\x2d\x30\x2e\x32\x36\x36\x34\x32\x20\x30\x2e\x34\x36\x32\x32\
+\x37\x2d\x30\x2e\x32\x33\x34\x32\x38\x20\x30\x2e\x38\x33\x38\x31\
+\x39\x2d\x30\x2e\x36\x30\x38\x32\x34\x20\x31\x2e\x30\x37\x33\x37\
+\x2d\x31\x2e\x30\x36\x38\x31\x20\x30\x2e\x32\x36\x37\x38\x31\x2d\
+\x30\x2e\x35\x32\x32\x38\x32\x20\x30\x2e\x32\x36\x37\x38\x31\x2d\
+\x31\x2e\x32\x30\x37\x33\x20\x30\x2e\x32\x36\x37\x38\x31\x2d\x32\
+\x2e\x35\x37\x36\x32\x76\x2d\x31\x31\x2e\x37\x33\x32\x63\x30\x2d\
+\x31\x2e\x33\x36\x38\x39\x20\x30\x2d\x32\x2e\x30\x35\x33\x33\x2d\
+\x30\x2e\x32\x36\x37\x38\x31\x2d\x32\x2e\x35\x37\x36\x32\x2d\x30\
+\x2e\x32\x33\x35\x35\x2d\x30\x2e\x34\x35\x39\x39\x31\x2d\x30\x2e\
+\x36\x31\x31\x34\x31\x2d\x30\x2e\x38\x33\x33\x38\x33\x2d\x31\x2e\
+\x30\x37\x33\x37\x2d\x31\x2e\x30\x36\x38\x32\x2d\x30\x2e\x34\x39\
+\x33\x33\x35\x2d\x30\x2e\x32\x35\x30\x30\x35\x2d\x31\x2e\x31\x32\
+\x39\x37\x2d\x30\x2e\x32\x36\x35\x34\x2d\x32\x2e\x33\x34\x33\x39\
+\x2d\x30\x2e\x32\x36\x36\x33\x34\x6d\x2d\x39\x2e\x38\x32\x37\x38\
+\x20\x30\x76\x32\x2e\x34\x34\x34\x31\x68\x39\x2e\x38\x32\x37\x38\
+\x76\x2d\x32\x2e\x34\x34\x34\x31\x6d\x2d\x39\x2e\x38\x32\x37\x38\
+\x20\x30\x76\x2d\x30\x2e\x33\x35\x38\x63\x30\x2d\x30\x2e\x35\x35\
+\x33\x33\x32\x20\x30\x2e\x32\x32\x30\x39\x35\x2d\x31\x2e\x30\x38\
+\x34\x20\x30\x2e\x36\x31\x34\x32\x34\x2d\x31\x2e\x34\x37\x35\x32\
+\x20\x30\x2e\x33\x39\x33\x32\x38\x2d\x30\x2e\x33\x39\x31\x32\x34\
+\x20\x30\x2e\x39\x32\x36\x37\x2d\x30\x2e\x36\x31\x31\x30\x35\x20\
+\x31\x2e\x34\x38\x32\x39\x2d\x30\x2e\x36\x31\x31\x30\x35\x68\x35\
+\x2e\x36\x33\x33\x35\x63\x30\x2e\x35\x35\x36\x31\x33\x20\x30\x20\
+\x31\x2e\x30\x38\x39\x37\x20\x30\x2e\x32\x31\x39\x38\x31\x20\x31\
+\x2e\x34\x38\x32\x39\x20\x30\x2e\x36\x31\x31\x30\x35\x73\x30\x2e\
+\x36\x31\x34\x32\x34\x20\x30\x2e\x39\x32\x31\x38\x39\x20\x30\x2e\
+\x36\x31\x34\x32\x34\x20\x31\x2e\x34\x37\x35\x32\x76\x30\x2e\x33\
+\x35\x38\x6d\x2d\x31\x2e\x32\x32\x38\x35\x20\x38\x2e\x35\x35\x34\
+\x36\x68\x2d\x33\x2e\x36\x38\x35\x34\x6d\x33\x2e\x36\x38\x35\x34\
+\x20\x34\x2e\x38\x38\x38\x34\x68\x2d\x33\x2e\x36\x38\x35\x34\x6d\
+\x2d\x33\x2e\x36\x38\x35\x34\x2d\x34\x2e\x38\x38\x38\x34\x68\x30\
+\x2e\x30\x31\x32\x32\x38\x35\x6d\x2d\x30\x2e\x30\x31\x32\x32\x38\
+\x35\x20\x34\x2e\x38\x38\x38\x34\x68\x30\x2e\x30\x31\x32\x32\x38\
+\x35\x22\x20\x73\x74\x72\x6f\x6b\x65\x3d\x22\x23\x30\x30\x30\x22\
+\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\x69\x6e\x65\x63\x61\x70\x3d\
+\x22\x72\x6f\x75\x6e\x64\x22\x20\x73\x74\x72\x6f\x6b\x65\x2d\x6c\
+\x69\x6e\x65\x6a\x6f\x69\x6e\x3d\x22\x72\x6f\x75\x6e\x64\x22\x20\
+\x73\x74\x72\x6f\x6b\x65\x2d\x77\x69\x64\x74\x68\x3d\x22\x32\x22\
+\x2f\x3e\x0a\x3c\x2f\x73\x76\x67\x3e\x0a\
+"
+
+qt_resource_name = b"\
+\x00\x06\
+\x07\x03\x7d\xc3\
+\x00\x69\
+\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\
+\x00\x05\
+\x00\x6d\x65\xb3\
+\x00\x66\
+\x00\x6f\x00\x6e\x00\x74\x00\x73\
+\x00\x09\
+\x09\xbe\x50\x14\
+\x00\x37\
+\x00\x2d\x00\x53\x00\x65\x00\x67\x00\x6d\x00\x65\x00\x6e\x00\x74\
+\x00\x06\
+\x06\xe0\xaf\xb2\
+\x00\x67\
+\x00\x69\x00\x74\x00\x68\x00\x75\x00\x62\
+\x00\x0a\
+\x0a\xc8\x01\x7e\
+\x00\x64\
+\x00\x69\x00\x73\x00\x63\x00\x75\x00\x73\x00\x73\x00\x69\x00\x6f\x00\x6e\
+\x00\x03\
+\x00\x00\x73\x57\
+\x00\x6c\
+\x00\x6f\x00\x67\
+\x00\x12\
+\x08\x44\xd2\x07\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x70\x00\x65\x00\x6e\x00\x64\x00\x69\x00\x6e\
+\x00\x67\
+\x00\x0f\
+\x03\xf2\x30\x8e\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x77\x00\x61\x00\x72\x00\x6e\
+\x00\x05\
+\x00\x7d\xeb\xbc\
+\x00\x77\
+\x00\x68\x00\x65\x00\x65\x00\x6c\
+\x00\x04\
+\x00\x07\x9f\x67\
+\x00\x73\
+\x00\x68\x00\x6f\x00\x77\
+\x00\x04\
+\x00\x07\x4c\xf4\
+\x00\x6e\
+\x00\x65\x00\x78\x00\x74\
+\x00\x0a\
+\x0b\xc6\x37\xb4\
+\x00\x73\
+\x00\x74\x00\x61\x00\x74\x00\x75\x00\x73\x00\x5f\x00\x6c\x00\x65\x00\x64\
+\x00\x07\
+\x08\xca\xa8\x74\
+\x00\x72\
+\x00\x65\x00\x73\x00\x74\x00\x61\x00\x72\x00\x74\
+\x00\x04\
+\x00\x06\xf6\x35\
+\x00\x68\
+\x00\x6f\x00\x6d\x00\x65\
+\x00\x0f\
+\x03\xf1\x2f\xfc\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x66\x00\x61\x00\x69\x00\x6c\
+\x00\x08\
+\x05\xe5\x51\xec\
+\x00\x6c\
+\x00\x6f\x00\x67\x00\x6f\x00\x5f\x00\x69\x00\x62\x00\x6c\
+\x00\x05\
+\x00\x69\xeb\x9b\
+\x00\x63\
+\x00\x68\x00\x65\x00\x63\x00\x6b\
+\x00\x08\
+\x08\xcd\x08\x23\
+\x00\x70\
+\x00\x72\x00\x65\x00\x76\x00\x69\x00\x6f\x00\x75\x00\x73\
+\x00\x04\
+\x00\x06\xec\x30\
+\x00\x68\
+\x00\x65\x00\x6c\x00\x70\
+\x00\x0b\
+\x0f\x0d\x12\xdf\
+\x00\x69\
+\x00\x62\x00\x6c\x00\x72\x00\x69\x00\x67\x00\x5f\x00\x6c\x00\x6f\x00\x67\x00\x6f\
+\x00\x0f\
+\x03\xf2\x8a\x00\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x73\x00\x6b\x00\x69\x00\x70\
+\x00\x05\
+\x00\x6e\x88\x43\
+\x00\x67\
+\x00\x72\x00\x61\x00\x6d\x00\x73\
+\x00\x07\
+\x07\x8c\x9c\xb4\
+\x00\x70\
+\x00\x72\x00\x65\x00\x73\x00\x65\x00\x6e\x00\x74\
+\x00\x03\
+\x00\x00\x69\xb7\
+\x00\x62\
+\x00\x75\x00\x67\
+\x00\x04\
+\x00\x06\xef\xa5\
+\x00\x68\
+\x00\x69\x00\x64\x00\x65\
+\x00\x15\
+\x0a\x2e\x2b\xfe\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x73\x00\x75\x00\x67\x00\x67\x00\x65\x00\x73\
+\x00\x74\x00\x69\x00\x6f\x00\x6e\
+\x00\x06\
+\x07\xaa\x79\x25\
+\x00\x73\
+\x00\x74\x00\x61\x00\x62\x00\x6c\x00\x65\
+\x00\x08\
+\x0c\xaa\x0d\x73\
+\x00\x73\
+\x00\x65\x00\x73\x00\x73\x00\x69\x00\x6f\x00\x6e\x00\x73\
+\x00\x05\
+\x00\x6d\x3c\x98\
+\x00\x66\
+\x00\x6c\x00\x75\x00\x73\x00\x68\
+\x00\x05\
+\x00\x67\x96\xc4\
+\x00\x61\
+\x00\x62\x00\x6f\x00\x75\x00\x74\
+\x00\x0f\
+\x03\xf1\x2c\xcf\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x69\x00\x6e\x00\x66\x00\x6f\
+\x00\x0f\
+\x03\xf2\x80\xa3\
+\x00\x76\
+\x00\x61\x00\x6c\x00\x69\x00\x64\x00\x61\x00\x74\x00\x69\x00\x6f\x00\x6e\x00\x5f\x00\x70\x00\x61\x00\x73\x00\x73\
+\x00\x05\
+\x00\x6e\x35\x85\
+\x00\x67\
+\x00\x6c\x00\x6f\x00\x62\x00\x65\
+\x00\x09\
+\x00\x69\x8c\xe4\
+\x00\x63\
+\x00\x6c\x00\x69\x00\x70\x00\x62\x00\x6f\x00\x61\x00\x72\x00\x64\
+"
+
+qt_resource_struct_v1 = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
+\x00\x00\x00\x12\x00\x02\x00\x00\x00\x01\x00\x00\x00\x22\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1f\x00\x00\x00\x03\
+\x00\x00\x01\xfa\x00\x00\x00\x00\x00\x01\x00\x00\xaf\x92\
+\x00\x00\x00\x66\x00\x00\x00\x00\x00\x01\x00\x00\x19\x35\
+\x00\x00\x01\x88\x00\x00\x00\x00\x00\x01\x00\x00\x3a\x46\
+\x00\x00\x02\x06\x00\x00\x00\x00\x00\x01\x00\x00\xb5\xc4\
+\x00\x00\x01\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x2d\x4a\
+\x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00\x28\x36\
+\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x26\x5c\
+\x00\x00\x02\x7c\x00\x00\x00\x00\x00\x01\x00\x00\xc4\x56\
+\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x00\xe0\x2b\
+\x00\x00\x01\x62\x00\x00\x00\x00\x00\x01\x00\x00\x37\x07\
+\x00\x00\x02\x6c\x00\x00\x00\x00\x00\x01\x00\x00\xc3\x32\
+\x00\x00\x02\xd4\x00\x00\x00\x00\x00\x01\x00\x00\xd9\x57\
+\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x00\xa4\x65\
+\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x04\
+\x00\x00\x02\x8c\x00\x00\x00\x00\x00\x01\x00\x00\xc6\xd7\
+\x00\x00\x01\x28\x00\x00\x00\x00\x00\x01\x00\x00\x2e\x62\
+\x00\x00\x00\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x3f\
+\x00\x00\x02\xb0\x00\x00\x00\x00\x00\x01\x00\x00\xd0\xbb\
+\x00\x00\x01\xb2\x00\x00\x00\x00\x00\x01\x00\x00\xa2\x4b\
+\x00\x00\x01\x4c\x00\x01\x00\x00\x00\x01\x00\x00\x30\x76\
+\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x12\x6c\
+\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\xa7\xe5\
+\x00\x00\x02\x44\x00\x00\x00\x00\x00\x01\x00\x00\xb8\xb8\
+\x00\x00\x00\x72\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x12\
+\x00\x00\x01\x06\x00\x00\x00\x00\x00\x01\x00\x00\x2a\x7c\
+\x00\x00\x01\x72\x00\x00\x00\x00\x00\x01\x00\x00\x39\x19\
+\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x00\xb8\x1b\
+\x00\x00\x00\x4c\x00\x00\x00\x00\x00\x01\x00\x00\x15\xe8\
+\x00\x00\x00\xec\x00\x00\x00\x00\x00\x01\x00\x00\x29\x55\
+\x00\x00\x02\x56\x00\x00\x00\x00\x00\x01\x00\x00\xbe\xee\
+\x00\x00\x01\x96\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x12\
+\x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+"
+
+qt_resource_struct_v2 = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x12\x00\x02\x00\x00\x00\x01\x00\x00\x00\x22\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1f\x00\x00\x00\x03\
+\x00\x00\x00\x00\x00\x00\x00\x00\
+\x00\x00\x01\xfa\x00\x00\x00\x00\x00\x01\x00\x00\xaf\x92\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x00\x66\x00\x00\x00\x00\x00\x01\x00\x00\x19\x35\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x01\x88\x00\x00\x00\x00\x00\x01\x00\x00\x3a\x46\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x02\x06\x00\x00\x00\x00\x00\x01\x00\x00\xb5\xc4\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x01\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x2d\x4a\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00\x28\x36\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x26\x5c\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x02\x7c\x00\x00\x00\x00\x00\x01\x00\x00\xc4\x56\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x00\xe0\x2b\
+\x00\x00\x01\x90\x11\x4f\x05\x62\
+\x00\x00\x01\x62\x00\x00\x00\x00\x00\x01\x00\x00\x37\x07\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x02\x6c\x00\x00\x00\x00\x00\x01\x00\x00\xc3\x32\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x02\xd4\x00\x00\x00\x00\x00\x01\x00\x00\xd9\x57\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x00\xa4\x65\
+\x00\x00\x01\x8e\x60\x1e\x68\x37\
+\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x1f\x04\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x02\x8c\x00\x00\x00\x00\x00\x01\x00\x00\xc6\xd7\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x01\x28\x00\x00\x00\x00\x00\x01\x00\x00\x2e\x62\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x00\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x1d\x3f\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x02\xb0\x00\x00\x00\x00\x00\x01\x00\x00\xd0\xbb\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x01\xb2\x00\x00\x00\x00\x00\x01\x00\x00\xa2\x4b\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x01\x4c\x00\x01\x00\x00\x00\x01\x00\x00\x30\x76\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x00\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x12\x6c\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x01\xe6\x00\x00\x00\x00\x00\x01\x00\x00\xa7\xe5\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x02\x44\x00\x00\x00\x00\x00\x01\x00\x00\xb8\xb8\
+\x00\x00\x01\x8e\x60\x1e\x68\x37\
+\x00\x00\x00\x72\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x12\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x01\x06\x00\x00\x00\x00\x00\x01\x00\x00\x2a\x7c\
+\x00\x00\x01\x8e\x60\x1e\x68\x37\
+\x00\x00\x01\x72\x00\x00\x00\x00\x00\x01\x00\x00\x39\x19\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x00\xb8\x1b\
+\x00\x00\x01\x8e\xf1\xa4\x09\xe2\
+\x00\x00\x00\x4c\x00\x00\x00\x00\x00\x01\x00\x00\x15\xe8\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe6\
+\x00\x00\x00\xec\x00\x00\x00\x00\x00\x01\x00\x00\x29\x55\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x02\x56\x00\x00\x00\x00\x00\x01\x00\x00\xbe\xee\
+\x00\x00\x01\x90\x0b\xf3\xf8\xe9\
+\x00\x00\x01\x96\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x12\
+\x00\x00\x01\x8e\x1f\x04\xa3\xe7\
+\x00\x00\x00\x22\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
+\x00\x00\x01\x8e\x60\x1e\x68\x37\
+"
+
+qt_version = [int(v) for v in QtCore.qVersion().split('.')]
+if qt_version < [5, 8, 0]:
+    rcc_version = 1
+    qt_resource_struct = qt_resource_struct_v1
+else:
+    rcc_version = 2
+    qt_resource_struct = qt_resource_struct_v2
+
+
+[docs] +def qInitResources(): + QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
+ + +
+[docs] +def qCleanupResources(): + QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data)
+ + +qInitResources() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/splash.html b/_modules/iblrig/gui/splash.html new file mode 100644 index 000000000..7d0206e31 --- /dev/null +++ b/_modules/iblrig/gui/splash.html @@ -0,0 +1,221 @@ + + + + + + iblrig.gui.splash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.splash

+from PyQt5 import QtCore
+from PyQt5.QtCore import QEasingCurve, QPoint, QPropertyAnimation, QThreadPool, QTimer
+from PyQt5.QtWidgets import QDialog
+from typing_extensions import override
+
+from iblrig import __version__ as version
+from iblrig.constants import COPYRIGHT_YEAR
+from iblrig.gui.tools import Worker
+from iblrig.gui.ui_splash import Ui_splash
+from iblrig.hardware_validation import Result, get_all_validators
+from iblrig.path_helper import load_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings
+
+
+
+[docs] +class Splash(QDialog, Ui_splash): + validation_results: list[Result] = [] + +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setupUi(self) + self.setWindowFlags(QtCore.Qt.SplashScreen | QtCore.Qt.FramelessWindowHint) + self.installEventFilter(self) + + # store arguments as members + self.hardware_settings = load_pydantic_yaml(HardwareSettings) + self.rig_settings = load_pydantic_yaml(RigSettings) + + # update a few strings + self.labelVersion.setText(f'v{version}') + self.labelCopyright.setText(f{COPYRIGHT_YEAR}, International Brain Laboratory') + + # extremely important animation + self.hat.setProperty('pos', QPoint(0, -250)) + self.animation = QPropertyAnimation(self.hat, b'pos') + self.animation.setEasingCurve(QEasingCurve.InQuad) + self.animation.setEndValue(QPoint(0, 40)) + self.animation.setDuration(500) + self.animation.start() + + # start timer for force close + QTimer.singleShot(20000, self.stop_and_close) + + # start validation worker + worker = Worker(self.validation) + worker.signals.finished.connect(self.close) + QThreadPool.globalInstance().tryStart(worker) + + self.show()
+ + +
+[docs] + def validation(self): + for validator in get_all_validators(): + validator_instance = validator(hardware_settings=self.hardware_settings, iblrig_settings=self.rig_settings) + self.labelStatus.setText(f'Validating {validator_instance.name} ...') + for result in validator_instance.run(): + self.validation_results.append(result)
+ + +
+[docs] + def stop_and_close(self): + self.close()
+ + +
+[docs] + @override + def close(self): + super().close()
+ + +
+[docs] + @override + def eventFilter(self, obj, event): + """Disregard all key-presses.""" + return obj is self and event.type() == QtCore.QEvent.KeyPress
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/tab_about.html b/_modules/iblrig/gui/tab_about.html new file mode 100644 index 000000000..5209d7d3f --- /dev/null +++ b/_modules/iblrig/gui/tab_about.html @@ -0,0 +1,179 @@ + + + + + + iblrig.gui.tab_about — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.tab_about

+import webbrowser
+
+from PyQt5.QtCore import QThreadPool
+from PyQt5.QtWidgets import QWidget
+
+from iblrig import __version__ as iblrig_version
+from iblrig.constants import COPYRIGHT_YEAR, URL_DISCUSSION, URL_DOC, URL_ISSUES, URL_REPO
+from iblrig.gui.tools import Worker
+from iblrig.gui.ui_tab_about import Ui_TabAbout
+from iblrig.tools import get_anydesk_id
+
+
+
+[docs] +class TabAbout(QWidget, Ui_TabAbout): +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setupUi(self) + + # set version & copyright strings + self.uiLabelCopyright.setText(f'**IBLRIG v{iblrig_version}**\n\n© {COPYRIGHT_YEAR}, International Brain Laboratory') + + # define actions for command link buttons + self.commandLinkButtonGitHub.clicked.connect(lambda: webbrowser.open(URL_REPO)) + self.commandLinkButtonDoc.clicked.connect(lambda: webbrowser.open(URL_DOC)) + self.commandLinkButtonIssues.clicked.connect(lambda: webbrowser.open(URL_ISSUES)) + self.commandLinkButtonDiscussion.clicked.connect(lambda: webbrowser.open(URL_DISCUSSION)) + + # try to obtain AnyDesk ID + worker = Worker(get_anydesk_id, silent=True) + worker.signals.result.connect(self.onGetAnydeskResult) + QThreadPool.globalInstance().tryStart(worker)
+ + +
+[docs] + def onGetAnydeskResult(self, result: str | None) -> None: + if result is not None: + self.uiLabelAnyDesk.setText(f'Your AnyDesk ID: {result}')
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/tab_data.html b/_modules/iblrig/gui/tab_data.html new file mode 100644 index 000000000..036f00dc9 --- /dev/null +++ b/_modules/iblrig/gui/tab_data.html @@ -0,0 +1,355 @@ + + + + + + iblrig.gui.tab_data — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.tab_data

+import platform
+import subprocess
+from datetime import datetime
+from typing import NamedTuple
+
+import pandas as pd
+from PyQt5.Qt import pyqtSlot
+from PyQt5.QtCore import (
+    QDateTime,
+    QModelIndex,
+    QRegExp,
+    QSettings,
+    QSortFilterProxyModel,
+    Qt,
+    QThread,
+    pyqtSignal,
+)
+from PyQt5.QtWidgets import QHeaderView, QStyledItemDelegate, QWidget
+
+from iblrig.gui.tools import DataFrameTableModel
+from iblrig.gui.ui_tab_data import Ui_TabData
+from iblrig.path_helper import get_local_and_remote_paths
+from iblrig.transfer_experiments import CopyState, SessionCopier
+from iblutil.util import dir_size
+
+if platform.system() == 'Windows':
+    from os import startfile
+
+COPY_STATE_STRINGS = {
+    CopyState.HARD_RESET: 'Hard Reset',
+    CopyState.NOT_REGISTERED: 'Not Registered',
+    CopyState.PENDING: 'Copy Pending',
+    CopyState.COMPLETE: 'Copy Complete',
+    CopyState.FINALIZED: 'Copy Finalized',
+}
+
+SESSIONS_GLOB = r'*/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/[0-9][0-9][0-9]/'
+
+
+
+[docs] +def sizeof_fmt(num, suffix='B'): + for unit in ('', 'K', 'M', 'G', 'T', 'P', 'E', 'Z'): + if abs(num) < 1024.0: + return f'{num:3.1f} {unit}{suffix}' + num /= 1024.0 + return f'{num:.1f} Y{suffix}'
+ + + +
+[docs] +class Column(NamedTuple): + name: str + hidden: bool = False + resizeMode: QHeaderView.ResizeMode = QHeaderView.Fixed + sectionWidth: int = 130
+ + + +COLUMNS = ( + Column(name='Directory', hidden=True), + Column(name='Subject', resizeMode=QHeaderView.Stretch), + Column(name='Date'), + Column(name='Copy Status', sectionWidth=100), + Column(name='Size', sectionWidth=75), +) + + +
+[docs] +class DataItemDelegate(QStyledItemDelegate): +
+[docs] + def initStyleOption(self, option, index): + super().initStyleOption(option, index) + header_text = index.model().headerData(index.column(), Qt.Horizontal, Qt.DisplayRole) + if 'Size' in header_text: + option.text = sizeof_fmt(index.data()) + option.displayAlignment = Qt.AlignRight | Qt.AlignVCenter
+
+ + + +
+[docs] +class TabData(QWidget, Ui_TabData): +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setupUi(self) + self.settings = QSettings() + self.localSubjectsPath = get_local_and_remote_paths().local_subjects_folder + + # create empty DataFrameTableModel + data = pd.DataFrame(None, index=[], columns=[c.name for c in COLUMNS]) + self.tableModel = DataFrameTableModel(df=data) + + # create filter proxy & assign it to view + self.tableProxy = QSortFilterProxyModel() + self.tableProxy.setSourceModel(self.tableModel) + self.tableProxy.setFilterKeyColumn(1) + + # define view + self.tableView.setModel(self.tableProxy) + header = self.tableView.horizontalHeader() + header.setDefaultAlignment(Qt.AlignLeft) + for idx, column in enumerate(COLUMNS): + self.tableView.setColumnHidden(idx, column.hidden) + if not column.hidden: + if column.resizeMode == QHeaderView.Fixed: + header.resizeSection(idx, column.sectionWidth) + else: + header.setSectionResizeMode(idx, column.resizeMode) + self.tableView.setItemDelegate(DataItemDelegate(self.tableView)) + self.tableView.sortByColumn( + self.settings.value('sortColumn', [c.name for c in COLUMNS].index('Date'), int), + self.settings.value('sortOrder', Qt.AscendingOrder, Qt.SortOrder), + ) + + # define worker for assembling data + self.dataWorker = DataWorker(self) + + # connect signals to slots + self.dataWorker.initialized.connect(self.tableModel.setDataFrame) + self.dataWorker.update.connect(self.tableModel.setData) + self.dataWorker.started.connect(lambda: self.pushButtonUpdate.setEnabled(False)) + self.dataWorker.lazyLoadComplete.connect(lambda: self.pushButtonUpdate.setEnabled(True)) + self.tableView.doubleClicked.connect(self._openDir) + self.tableView.horizontalHeader().sectionClicked.connect(self._storeSort) + self.pushButtonUpdate.clicked.connect(self.dataWorker.start) + self.lineEditFilter.textChanged.connect(self._filter)
+ + + @pyqtSlot(str) + def _filter(self, text: str): + self.tableProxy.setFilterRegExp(QRegExp(text, Qt.CaseInsensitive)) + +
+[docs] + def showEvent(self, a0): + if self.tableModel.rowCount() == 0: + self.dataWorker.start()
+ + + @pyqtSlot(QModelIndex) + def _openDir(self, index: QModelIndex): + directory = self.tableView.model().itemData(index.siblingAtColumn(0))[0] + if platform.system() == 'Windows': + startfile(directory) + elif platform.system() == 'Darwin': + subprocess.Popen(['open', directory]) + else: + subprocess.Popen(['xdg-open', directory]) + + @pyqtSlot(int) + def _storeSort(self, index: int): + self.settings.setValue('sortColumn', self.tableView.horizontalHeader().sortIndicatorSection()) + self.settings.setValue('sortOrder', self.tableView.horizontalHeader().sortIndicatorOrder())
+ + + +
+[docs] +class DataWorker(QThread): + initialized = pyqtSignal(pd.DataFrame) + update = pyqtSignal(QModelIndex, object) + lazyLoadComplete = pyqtSignal() + +
+[docs] + def __init__(self, parent: TabData): + super().__init__(parent) + self.localSubjectsPath = parent.localSubjectsPath + self.tableModel = parent.tableModel + self.tableModel.modelReset.connect(self.lazyLoadStatus)
+ + +
+[docs] + def run(self): + data = [] + for session_dir in self.localSubjectsPath.glob(SESSIONS_GLOB): + # make sure we're dealing with a directory + if not session_dir.is_dir(): + continue + + # get folder creation time (cross-check with name of directory) + date = datetime.strptime(session_dir.parent.name, '%Y-%m-%d') + time = datetime.fromtimestamp(session_dir.stat().st_ctime) + date = time if time.date() == date.date() else date + + # append data + data.append( + [ + session_dir, + session_dir.parents[1].name, + QDateTime.fromTime_t(int(date.timestamp())), + '', # will be lazy-loaded in a separate step + float(dir_size(session_dir)), + ] + ) + data = pd.DataFrame(data=data, columns=[c.name for c in COLUMNS]) + self.initialized.emit(data)
+ + +
+[docs] + def lazyLoadStatus(self): + col_status = self.tableModel.dataFrame.columns.get_loc('Copy Status') + for row, row_data in self.tableModel.dataFrame.iterrows(): + state = SessionCopier(row_data['Directory']).state + state = COPY_STATE_STRINGS.get(state, 'N/A') + index = self.tableModel.index(row, col_status) + self.update.emit(index, state) + self.lazyLoadComplete.emit()
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/tab_docs.html b/_modules/iblrig/gui/tab_docs.html new file mode 100644 index 000000000..cea3d584d --- /dev/null +++ b/_modules/iblrig/gui/tab_docs.html @@ -0,0 +1,217 @@ + + + + + + iblrig.gui.tab_docs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.tab_docs

+import webbrowser
+
+from PyQt5.QtCore import QUrl
+from PyQt5.QtWebEngineWidgets import QWebEnginePage
+from PyQt5.QtWidgets import QWidget
+from typing_extensions import override
+
+from iblrig.constants import URL_DOC
+from iblrig.gui.ui_tab_docs import Ui_TabDocs
+
+
+
+[docs] +class TabDocs(QWidget, Ui_TabDocs): +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setupUi(self) + + # connect signals to slots + self.uiPushWebHome.clicked.connect(lambda: self.webEngineView.load(QUrl(URL_DOC))) + self.uiPushWebBack.clicked.connect(lambda: self.webEngineView.back()) + self.uiPushWebForward.clicked.connect(lambda: self.webEngineView.forward()) + self.uiPushWebBrowser.clicked.connect(lambda: webbrowser.open(str(self.webEngineView.url().url()))) + self.webEngineView.urlChanged.connect(self._on_doc_url_changed) + + # initialize webEngineView + self.webEngineView.setPage(CustomWebEnginePage(self)) + self.webEngineView.setUrl(QUrl(URL_DOC))
+ + + def _on_doc_url_changed(self): + self.uiPushWebBack.setEnabled(len(self.webEngineView.history().backItems(1)) > 0) + self.uiPushWebForward.setEnabled(len(self.webEngineView.history().forwardItems(1)) > 0)
+ + + +
+[docs] +class CustomWebEnginePage(QWebEnginePage): + """ + Custom implementation of QWebEnginePage to handle navigation requests. + + This class overrides the acceptNavigationRequest method to handle link clicks. + If the navigation type is a link click and the clicked URL does not start with + a specific prefix (URL_DOC), it opens the URL in the default web browser. + Otherwise, it delegates the handling to the base class. + + Adapted from: https://www.pythonguis.com/faq/qwebengineview-open-links-new-window/ + """ + +
+[docs] + @override + def acceptNavigationRequest(self, url: QUrl, navigationType: QWebEnginePage.NavigationType, is_main_frame: bool): + """ + Decide whether to allow or block a navigation request. + + Parameters + ---------- + url : QUrl + The URL being navigated to. + + navigationType : QWebEnginePage.NavigationType + The type of navigation request. + + is_main_frame : bool + Indicates whether the request is for the main frame. + + Returns + ------- + bool + True if the navigation request is accepted, False otherwise. + """ + if navigationType == QWebEnginePage.NavigationTypeLinkClicked and not url.url().startswith(URL_DOC): + webbrowser.open(url.url()) + return False + return super().acceptNavigationRequest(url, navigationType, is_main_frame)
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/tab_log.html b/_modules/iblrig/gui/tab_log.html new file mode 100644 index 000000000..6c2c90531 --- /dev/null +++ b/_modules/iblrig/gui/tab_log.html @@ -0,0 +1,239 @@ + + + + + + iblrig.gui.tab_log — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.tab_log

+from PyQt5.QtCore import QSettings, pyqtSlot
+from PyQt5.QtGui import QBrush, QColorConstants, QFont
+from PyQt5.QtWidgets import QApplication, QWidget
+
+from iblrig.gui.ui_tab_log import Ui_TabLog
+
+
+
+[docs] +class TabLog(QWidget, Ui_TabLog): +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setupUi(self) + self.settings = QSettings() + + font = QFont('Monospace') + font.setStyleHint(QFont.TypeWriter) + self.plainTextEditLog.setFont(font) + + self.pushButtonClipboard.setEnabled(False) + self.pushButtonClipboard.clicked.connect(self.copyToClipboard) + + self.spinBoxFontSize.valueChanged.connect(self.setFontSize) + self.spinBoxFontSize.setValue(self.settings.value('font_size', 11, int))
+ + +
+[docs] + @pyqtSlot() + def clear(self): + """Clear the log.""" + self.pushButtonClipboard.setEnabled(False) + self.plainTextEditLog.clear()
+ + +
+[docs] + @pyqtSlot(str, str) + def appendText(self, text: str, color: str = 'White'): + """ + Append text to the log. + + Parameters + ---------- + text : str + The text to append. + color : str, optional + The color of the text. Should be a valid color name recognized by + QtGui.QColorConstants. Defaults to 'White'. + """ + self.pushButtonClipboard.setEnabled(True) + self.setLogColor(color) + self.plainTextEditLog.appendPlainText(text)
+ + +
+[docs] + @pyqtSlot() + def copyToClipboard(self): + """Copy the log contents to the clipboard as a markdown code-block.""" + text = f'"""\n{self.plainTextEditLog.toPlainText()}\n"""' + QApplication.clipboard().setText(text)
+ + +
+[docs] + @pyqtSlot(int) + def setFontSize(self, fontSize: int): + """ + Set the font size of the log-widget's contents. + + Parameters + ---------- + fontSize : int + Font size of the log-widget's contents in points. + """ + font = self.plainTextEditLog.font() + font.setPointSize(fontSize) + self.plainTextEditLog.setFont(font) + self.settings.setValue('font_size', fontSize)
+ + +
+[docs] + def setLogColor(self, colorName: str): + """ + Set the foreground color of characters in the log widget. + + Parameters + ---------- + colorName : str, optional + The name of the color to set. Default is 'White'. Should be a valid color name + recognized by QtGui.QColorConstants. If the provided color name is not found, + it defaults to QtGui.QColorConstants.White. + """ + color = getattr(QColorConstants, colorName, QColorConstants.White) + char_format = self.plainTextEditLog.currentCharFormat() + char_format.setForeground(QBrush(color)) + self.plainTextEditLog.setCurrentCharFormat(char_format)
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/tools.html b/_modules/iblrig/gui/tools.html new file mode 100644 index 000000000..8b017920b --- /dev/null +++ b/_modules/iblrig/gui/tools.html @@ -0,0 +1,892 @@ + + + + + + iblrig.gui.tools — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.tools

+import argparse
+import logging
+import subprocess
+import sys
+import traceback
+from collections.abc import Callable
+from inspect import signature
+from pathlib import Path
+from shutil import disk_usage
+from typing import Any
+
+import numpy as np
+import pandas as pd
+from PyQt5 import QtGui
+from PyQt5.QtCore import (
+    QAbstractTableModel,
+    QModelIndex,
+    QObject,
+    QRunnable,
+    Qt,
+    QThreadPool,
+    QVariant,
+    pyqtProperty,
+    pyqtSignal,
+    pyqtSlot,
+)
+from PyQt5.QtGui import QStandardItem, QStandardItemModel
+from PyQt5.QtWidgets import QAction, QLineEdit, QListView, QProgressBar, QPushButton
+from requests import HTTPError
+
+from iblrig.constants import BASE_PATH
+from iblrig.gui import resources_rc  # noqa: F401
+from iblrig.net import get_remote_devices
+from iblrig.pydantic_definitions import RigSettings
+from iblutil.util import dir_size
+from one.webclient import AlyxClient
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +def convert_uis(): + """A wrapper for PyQt5's pyuic5 and pyrcc5, set up for development on iblrig.""" + parser = argparse.ArgumentParser() + parser.add_argument('pattern', nargs='?', default='*.*', type=str) + args = parser.parse_args() + + gui_path = BASE_PATH.joinpath('iblrig', 'gui') + files = set([f for f in gui_path.glob(args.pattern)]) + + for filename_in in files.intersection(gui_path.glob('*.qrc')): + rel_path_in = filename_in.relative_to(BASE_PATH) + rel_path_out = rel_path_in.with_stem(rel_path_in.stem + '_rc').with_suffix('.py') + args = ['pyrcc5', str(rel_path_in), '-o', str(rel_path_out)] + print(' '.join(args)) + subprocess.check_output(args, cwd=BASE_PATH) + + for filename_in in files.intersection(gui_path.glob('*.ui')): + rel_path_in = filename_in.relative_to(BASE_PATH) + rel_path_out = rel_path_in.with_suffix('.py') + args = ['pyuic5', str(rel_path_in), '-o', str(rel_path_out), '-x', '--import-from=iblrig.gui'] + print(' '.join(args)) + subprocess.check_output(args, cwd=BASE_PATH)
+ + + +
+[docs] +class WorkerSignals(QObject): + """ + Signals used by the Worker class to communicate with the main thread. + + Attributes + ---------- + finished : pyqtSignal + Signal emitted when the worker has finished its task. + + error : pyqtSignal(tuple) + Signal emitted when an error occurs. The signal carries a tuple with the exception type, + exception value, and the formatted traceback. + + result : pyqtSignal(Any) + Signal emitted when the worker has successfully completed its task. The signal carries + the result of the task. + + progress : pyqtSignal(int) + Signal emitted to report progress during the task. The signal carries an integer value. + """ + + finished = pyqtSignal() + error = pyqtSignal(tuple) + result = pyqtSignal(object) + progress = pyqtSignal(int)
+ + + +
+[docs] +class DiskSpaceIndicator(QProgressBar): + """A custom progress bar widget that indicates the disk space usage of a specified directory.""" + +
+[docs] + def __init__(self, *args, directory: Path | None, percent_threshold: int = 90, **kwargs): + """ + Initialize the DiskSpaceIndicator with the specified directory and threshold percentage. + + Parameters + ---------- + *args : tuple + Variable length argument list (passed to QProgressBar). + directory : Path or None + The directory path to monitor for disk space usage. + percent_threshold : int, optional + The threshold percentage at which the progress bar changes color to red. Default is 90. + **kwargs : dict + Arbitrary keyword arguments (passed to QProgressBar). + """ + super().__init__(*args, **kwargs) + self._directory = directory + self._percent_threshold = percent_threshold + self._percent_full = float('nan') + self.setEnabled(False) + if self._directory is not None: + self.update_data()
+ + +
+[docs] + def update_data(self): + """Update the disk space information.""" + worker = Worker(self._get_size) + worker.signals.result.connect(self._on_get_size_result) + QThreadPool.globalInstance().start(worker)
+ + + @property + def critical(self) -> bool: + """True if the disk space usage is above the given threshold percentage.""" + return self._percent_full > self._percent_threshold + + def _get_size(self): + """Get the disk usage information for the specified directory.""" + usage = disk_usage(self._directory.anchor) + self._percent_full = usage.used / usage.total * 100 + self._gigs_dir = dir_size(self._directory) / 1024**3 + self._gigs_free = usage.free / 1024**3 + + def _on_get_size_result(self, result): + """Handle the result of getting disk usage information and update the progress bar accordingly.""" + self.setEnabled(True) + self.setValue(round(self._percent_full)) + if self.critical: + p = self.palette() + p.setColor(QtGui.QPalette.Highlight, QtGui.QColor('red')) + self.setPalette(p) + self.setStatusTip(f'{self._directory}: {self._gigs_dir:.1f} GB • ' f'available space: {self._gigs_free:.1f} GB')
+ + + +
+[docs] +class Worker(QRunnable): + """ + A generic worker class for executing functions concurrently in a separate thread. + + This class is designed to run functions concurrently in a separate thread and emit signals + to communicate the results or errors back to the main thread. + + Adapted from: https://www.pythonguis.com/tutorials/multithreading-pyqt-applications-qthreadpool/ + + Attributes + ---------- + fn : Callable + The function to be executed concurrently. + + args : tuple + Positional arguments for the function. + + kwargs : dict + Keyword arguments for the function. + + signals : WorkerSignals + An instance of WorkerSignals used to emit signals. + + Methods + ------- + run() -> None + The main entry point for running the worker. Executes the provided function and + emits signals accordingly. + """ + +
+[docs] + def __init__(self, fn: Callable[..., Any], *args: Any, **kwargs: Any): + """ + Initialize the Worker instance. + + Parameters + ---------- + fn : Callable + The function to be executed concurrently. + + *args : tuple + Positional arguments for the function. + + **kwargs : dict + Keyword arguments for the function. + """ + super().__init__() + self.fn = fn + self.args = args + self.kwargs = kwargs + self.signals: WorkerSignals = WorkerSignals() + if 'progress_callback' in signature(fn).parameters: + self.kwargs['progress_callback'] = self.signals.progress
+ + +
+[docs] + def run(self) -> None: + """ + Execute the provided function and emit signals accordingly. + + This method is the main entry point for running the worker. It executes the provided + function and emits signals to communicate the results or errors back to the main thread. + + Returns + ------- + None + """ + try: + result = self.fn(*self.args, **self.kwargs) + except: # noqa: E722 + # Handle exceptions and emit error signal with exception details + traceback.print_exc() + exctype, value = sys.exc_info()[:2] + self.signals.error.emit((exctype, value, traceback.format_exc())) + else: + # Emit result signal with the result of the task + self.signals.result.emit(result) + finally: + # Emit the finished signal to indicate completion + self.signals.finished.emit()
+
+ + + +
+[docs] +class DataFrameTableModel(QAbstractTableModel): +
+[docs] + def __init__(self, *args, df: pd.DataFrame, **kwargs): + super().__init__(*args, **kwargs) + self._dataFrame = df
+ + + def dataFrame(self): + return self._dataFrame + +
+[docs] + def setDataFrame(self, data_frame: pd.DataFrame): + self.beginResetModel() + self._dataFrame = data_frame.copy() + self.endResetModel()
+ + + dataFrame = pyqtProperty(pd.DataFrame, fget=dataFrame, fset=setDataFrame) + +
+[docs] + def headerData(self, section, orientation, role=...): + """ + Get the header data for the specified section. + + Parameters + ---------- + section : int + The section index. + orientation : Qt.Orientation + The orientation of the header. + role : int, optional + The role of the header data. + + Returns + ------- + QVariant + The header data. + """ + if role == Qt.DisplayRole: + if orientation == Qt.Horizontal: + return str(self._dataFrame.columns[section]) + else: + return str(self._dataFrame.index[section])
+ + +
+[docs] + def rowCount(self, parent=...): + """ + Get the number of rows in the model. + + Parameters + ---------- + parent : QModelIndex, optional + The parent index. + + Returns + ------- + int + The number of rows. + """ + if isinstance(parent, QModelIndex) and parent.isValid(): + return 0 + return self.dataFrame.shape[0]
+ + +
+[docs] + def columnCount(self, parent=...): + """ + Get the number of columns in the model. + + Parameters + ---------- + parent : QModelIndex, optional + The parent index. + + Returns + ------- + int + The number of columns. + """ + if isinstance(parent, QModelIndex) and parent.isValid(): + return 0 + return self.dataFrame.shape[1]
+ + +
+[docs] + def data(self, index, role=...): + """ + Get the data for the specified index. + + Parameters + ---------- + index : QModelIndex + The index of the data. + role : int, optional + The role of the data. + + Returns + ------- + QVariant + The data for the specified index. + """ + if index.isValid(): + row = self._dataFrame.index[index.row()] + col = self._dataFrame.columns[index.column()] + dat = self._dataFrame.iloc[row][col] + if role == Qt.DisplayRole: + if isinstance(dat, np.generic): + return dat.item() + return dat + return QVariant()
+ + +
+[docs] + def sort(self, column, order=...): + """ + Sort the data based on the specified column and order. + + Parameters + ---------- + column : int + The column index to sort by. + order : Qt.SortOrder, optional + The sort order. + """ + self.layoutAboutToBeChanged.emit() + col_name = self._dataFrame.columns.values[column] + self._dataFrame.sort_values(by=col_name, ascending=order == Qt.AscendingOrder, inplace=True) + self._dataFrame.reset_index(inplace=True, drop=True) + self.layoutChanged.emit()
+ + +
+[docs] + def setData(self, index, value, role=Qt.DisplayRole): + """ + Set data at the specified index with the given value. + + Parameters + ---------- + index : QModelIndex + The index where the data will be set. + value : Any + The new value to be set at the specified index. + role : int, optional + The role of the data. Default is Qt.DisplayRole. + """ + if index.isValid(): + row = self._dataFrame.index[index.row()] + col = self._dataFrame.columns[index.column()] + self._dataFrame.at[row, col] = value + self.dataChanged.emit(index, index, [role])
+
+ + + +
+[docs] +class RemoteDevicesListView(QListView): +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setMouseTracking(True) # needed for status tips
+ + +
+[docs] + def getDevices(self): + out = [] + for idx in self.selectedIndexes(): + out.append(self.model().itemData(idx)[Qt.UserRole]) + return out
+
+ + + +
+[docs] +class RemoteDevicesItemModel(QStandardItemModel): +
+[docs] + def __init__(self, *args, iblrig_settings: RigSettings, **kwargs): + super().__init__(*args, **kwargs) + self.remote_devices = get_remote_devices(iblrig_settings=iblrig_settings) + self.update()
+ + +
+[docs] + @pyqtSlot() + def update(self): + self.clear() + for device_name, device_address in self.remote_devices.items(): + item = QStandardItem(device_name) + item.setStatusTip(f'Remote Device "{device_name}" - {device_address}') + item.setData(device_name, Qt.UserRole) + self.appendRow(item)
+
+ + + +
+[docs] +class AlyxObject(QObject): + """ + A class to manage user authentication with an AlyxClient. + + This class provides methods to log in and log out users, emitting signals to indicate changes in authentication status. + + Parameters + ---------- + alyxUrl : str, optional + The base URL for the Alyx API. If provided, an AlyxClient will be created. + alyxClient : AlyxClient, optional + An existing AlyxClient instance. If provided, it will be used for authentication. + + Attributes + ---------- + isLoggedIn : bool + Indicates whether a user is currently logged in. + username : str or None + The username of the logged-in user, or None if not logged in. + statusChanged : pyqtSignal + Emitted when the login status changes (logged in or out). The signal carries a boolean indicating the new status. + loggedIn : pyqtSignal + Emitted when a user logs in. The signal carries a string representing the username. + loggedOut : pyqtSignal + Emitted when a user logs out. The signal carries a string representing the username. + loginFailed : pyqtSignal + Emitted when a login attempt fails. The signal carries a string representing the username. + """ + + statusChanged = pyqtSignal(bool) + loggedIn = pyqtSignal(str) + loggedOut = pyqtSignal(str) + loginFailed = pyqtSignal(str) + +
+[docs] + def __init__(self, *args, alyxUrl: str | None = None, alyxClient: AlyxClient | None = None, **kwargs): + """ + Initializes the AlyxObject. + + Parameters + ---------- + *args : tuple + Positional arguments for QObject. + alyxUrl : str, optional + The base URL for the Alyx API. + alyxClient : AlyxClient, optional + An existing AlyxClient instance. + **kwargs : dict + Keyword arguments for QObject. + """ + super().__init__(*args, **kwargs) + self._icon = super().icon() + + if alyxUrl is not None: + self.client = AlyxClient(base_url=alyxUrl, silent=True) + else: + self.client = alyxClient
+ + +
+[docs] + @pyqtSlot(str) + @pyqtSlot(str, str) + @pyqtSlot(str, str, bool) + def logIn(self, username: str, password: str | None = None, cacheToken: bool = False) -> bool: + """ + Logs in a user with the provided username and password. + + Emits the loggedIn and statusChanged signals if the logout is successful, and the loginFailed signal otherwise. + + Parameters + ---------- + username : str + The username of the user attempting to log in. + password : str or None, optional + The password of the user. If None, the login will proceed without a password. + cacheToken : bool, optional + Whether to cache the authentication token. + + Returns + ------- + bool + True if the login was successful, False otherwise. + """ + if self.client is None: + return False + try: + self.client.authenticate(username, password, cache_token=cacheToken, force=password is not None) + except HTTPError as e: + if e.errno == 400 and any(x in e.response.text for x in ('credentials', 'required')): + log.error(e.filename) + self.loginFailed.emit(username) + else: + raise e + if status := self.client.is_logged_in and self.client.user == username: + log.debug(f"Logged into {self.client.base_url} as user '{username}'") + self.statusChanged.emit(True) + self.loggedIn.emit(username) + return status
+ + +
+[docs] + @pyqtSlot() + def logOut(self) -> None: + """ + Logs out the currently logged-in user. + + Emits the loggedOut and statusChanged signals if the logout is successful. + """ + if self.client is None or not self.isLoggedIn: + return + username = self.client.user + self.client.logout() + if not (connected := self.client.is_logged_in): + log.debug(f"User '{username}' logged out of {self.client.base_url}") + self.statusChanged.emit(connected) + self.loggedOut.emit(username)
+ + + @property + def isLoggedIn(self): + """Indicates whether a user is currently logged in.""" + return self.client.is_logged_in if isinstance(self.client, AlyxClient) else False + + @property + def username(self) -> str | None: + """The username of the logged-in user, or None if not logged in.""" + return self.client.user if self.isLoggedIn else None
+ + + +
+[docs] +class LineEditAlyxUser(QLineEdit): + """ + A custom QLineEdit widget for managing user login with an AlyxObject. + + This widget displays a checkmark icon to indicate the connection status + and allows the user to input their username for logging in. + + Parameters + ---------- + *args : tuple + Positional arguments passed to the QLineEdit constructor. + alyx : AlyxObject + An instance of AlyxObject used to manage login and connection status. + **kwargs : dict + Keyword arguments passed to the QLineEdit constructor. + """ + +
+[docs] + def __init__(self, *args, alyx: AlyxObject, **kwargs): + """ + Initializes the LineEditAlyxUser widget. + + Sets up the checkmark icon, connects signals for login status, + and configures the line edit based on the AlyxObject's state. + + Parameters + ---------- + *args : tuple + Positional arguments passed to the QLineEdit constructor. + alyx : AlyxObject + An instance of AlyxObject. + **kwargs : dict + Keyword arguments passed to the QLineEdit constructor. + """ + super().__init__(*args, **kwargs) + self.alyx = alyx + + # Use a QAction to indicate the connection status + self._checkmarkIcon = QAction(parent=self, icon=QtGui.QIcon(':/images/check')) + self.addAction(self._checkmarkIcon, self.ActionPosition.TrailingPosition) + + if self.alyx.client is None: + self.setEnabled(False) + else: + self.setPlaceholderText('not logged in') + self.alyx.statusChanged.connect(self._onStatusChanged) + self.returnPressed.connect(self.logIn) + self._onStatusChanged(self.alyx.isLoggedIn)
+ + + @pyqtSlot(bool) + def _onStatusChanged(self, connected: bool): + """Set some of the widget's properties depending on the current connection-status.""" + self._checkmarkIcon.setVisible(connected) + self._checkmarkIcon.setToolTip(f'Connected to {self.alyx.client.base_url}' if connected else '') + self.setText(self.alyx.username or '') + self.setReadOnly(connected) + +
+[docs] + @pyqtSlot() + def logIn(self): + """Attempt to log in using the line edit's current text.""" + self.alyx.logIn(self.text())
+
+ + + +
+[docs] +class StatefulButton(QPushButton): + """ + A QPushButton that maintains an active/inactive state and emits different signals + based on its state when clicked. + + Parameters + ---------- + active : bool, optional + Initial state of the button (default is False). + + Attributes + ---------- + clickedWhileActive : pyqtSignal + Emitted when the button is clicked while it is in the active state. + clickedWhileInactive : pyqtSignal + Emitted when the button is clicked while it is in the inactive state. + stateChanged : pyqtSignal + Emitted when the button's state has changed. The signal carries the new state. + """ + + clickedWhileActive = pyqtSignal() + clickedWhileInactive = pyqtSignal() + stateChanged = pyqtSignal(bool) + +
+[docs] + def __init__(self, *args, active: bool = False, **kwargs): + """ + Initialize the StateButton with the specified active state. + + Parameters + ---------- + *args : tuple + Positional arguments to be passed to the QPushButton constructor. + active : bool, optional + Initial state of the button (default is False). + **kwargs : dict + Keyword arguments to be passed to the QPushButton constructor. + """ + super().__init__(*args, **kwargs) + self._isActive = active + self.clicked.connect(self._onClick)
+ + + @pyqtProperty(bool) + def isActive(self) -> bool: + """ + Get the active state of the button. + + Returns + ------- + bool + True if the button is active, False otherwise. + """ + return self._isActive + +
+[docs] + @pyqtSlot(bool) + def setActive(self, active: bool): + """ + Set the active state of the button. + + Emits `stateChanged` if the state has changed. + + Parameters + ---------- + active : bool + The new active state of the button. + """ + if self._isActive != active: + self._isActive = active + self.stateChanged.emit(self._isActive)
+ + + @pyqtSlot() + def _onClick(self): + """ + Handle the button click event. + + Emits `clickedWhileActive` if the button is active, + otherwise emits `clickedWhileInactive`. + """ + if self._isActive: + self.clickedWhileActive.emit() + else: + self.clickedWhileInactive.emit()
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_frame2ttl.html b/_modules/iblrig/gui/ui_frame2ttl.html new file mode 100644 index 000000000..0f257d31e --- /dev/null +++ b/_modules/iblrig/gui/ui_frame2ttl.html @@ -0,0 +1,246 @@ + + + + + + iblrig.gui.ui_frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_frame2ttl

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_frame2ttl.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_frame2ttl(object): +
+[docs] + def setupUi(self, frame2ttl): + frame2ttl.setObjectName("frame2ttl") + frame2ttl.resize(200, 200) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(frame2ttl.sizePolicy().hasHeightForWidth()) + frame2ttl.setSizePolicy(sizePolicy) + frame2ttl.setMinimumSize(QtCore.QSize(200, 200)) + frame2ttl.setMaximumSize(QtCore.QSize(200, 200)) + self.verticalLayout_2 = QtWidgets.QVBoxLayout(frame2ttl) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.formLayout = QtWidgets.QFormLayout() + self.formLayout.setObjectName("formLayout") + self.uiLabelLight = QtWidgets.QLabel(frame2ttl) + self.uiLabelLight.setObjectName("uiLabelLight") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.uiLabelLight) + self.uiLabelDark = QtWidgets.QLabel(frame2ttl) + self.uiLabelDark.setObjectName("uiLabelDark") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uiLabelDark) + self.uiLabelHardware = QtWidgets.QLabel(frame2ttl) + self.uiLabelHardware.setObjectName("uiLabelHardware") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.uiLabelHardware) + self.uiLabelFirmware = QtWidgets.QLabel(frame2ttl) + self.uiLabelFirmware.setObjectName("uiLabelFirmware") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.uiLabelFirmware) + self.uiLabelPort = QtWidgets.QLabel(frame2ttl) + self.uiLabelPort.setObjectName("uiLabelPort") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.uiLabelPort) + self.uiLabelPortValue = QtWidgets.QLabel(frame2ttl) + self.uiLabelPortValue.setText("") + self.uiLabelPortValue.setObjectName("uiLabelPortValue") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.uiLabelPortValue) + self.uiLabelHardwareValue = QtWidgets.QLabel(frame2ttl) + self.uiLabelHardwareValue.setText("") + self.uiLabelHardwareValue.setObjectName("uiLabelHardwareValue") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.uiLabelHardwareValue) + self.uiLabelFirmwareValue = QtWidgets.QLabel(frame2ttl) + self.uiLabelFirmwareValue.setText("") + self.uiLabelFirmwareValue.setObjectName("uiLabelFirmwareValue") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.uiLabelFirmwareValue) + self.uiLabelLightValue = QtWidgets.QLabel(frame2ttl) + self.uiLabelLightValue.setText("") + self.uiLabelLightValue.setObjectName("uiLabelLightValue") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiLabelLightValue) + self.uiLabelDarkValue = QtWidgets.QLabel(frame2ttl) + self.uiLabelDarkValue.setText("") + self.uiLabelDarkValue.setObjectName("uiLabelDarkValue") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiLabelDarkValue) + self.verticalLayout_2.addLayout(self.formLayout) + spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_2.addItem(spacerItem) + self.uiLabelResult = QtWidgets.QLabel(frame2ttl) + self.uiLabelResult.setText("") + self.uiLabelResult.setObjectName("uiLabelResult") + self.verticalLayout_2.addWidget(self.uiLabelResult) + spacerItem1 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_2.addItem(spacerItem1) + self.buttonBox = QtWidgets.QDialogButtonBox(frame2ttl) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_2.addWidget(self.buttonBox) + + self.retranslateUi(frame2ttl) + self.buttonBox.accepted.connect(frame2ttl.accept) # type: ignore + self.buttonBox.rejected.connect(frame2ttl.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(frame2ttl)
+ + +
+[docs] + def retranslateUi(self, frame2ttl): + _translate = QtCore.QCoreApplication.translate + frame2ttl.setWindowTitle(_translate("frame2ttl", "Frame2TTL Calibration")) + self.uiLabelLight.setText(_translate("frame2ttl", "Light Threshold:")) + self.uiLabelDark.setText(_translate("frame2ttl", "Dark Threshold:")) + self.uiLabelHardware.setText(_translate("frame2ttl", "Hardware Revision:")) + self.uiLabelFirmware.setText(_translate("frame2ttl", "Firmware Version:")) + self.uiLabelPort.setText(_translate("frame2ttl", "Serial Port:"))
+
+ + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + frame2ttl = QtWidgets.QDialog() + ui = Ui_frame2ttl() + ui.setupUi(frame2ttl) + frame2ttl.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_login.html b/_modules/iblrig/gui/ui_login.html new file mode 100644 index 000000000..0b0fca879 --- /dev/null +++ b/_modules/iblrig/gui/ui_login.html @@ -0,0 +1,237 @@ + + + + + + iblrig.gui.ui_login — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_login

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig/gui/ui_login.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.9
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_login(object): +
+[docs] + def setupUi(self, login): + login.setObjectName("login") + login.setWindowModality(QtCore.Qt.ApplicationModal) + login.resize(349, 166) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(login.sizePolicy().hasHeightForWidth()) + login.setSizePolicy(sizePolicy) + login.setMinimumSize(QtCore.QSize(0, 130)) + self.verticalLayout = QtWidgets.QVBoxLayout(login) + self.verticalLayout.setObjectName("verticalLayout") + self.widget = QtWidgets.QWidget(login) + self.widget.setObjectName("widget") + self.formLayout = QtWidgets.QFormLayout(self.widget) + self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout.setContentsMargins(0, 0, 0, 0) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(self.widget) + self.label.setObjectName("label") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label) + self.lineEditUsername = QtWidgets.QLineEdit(self.widget) + self.lineEditUsername.setObjectName("lineEditUsername") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lineEditUsername) + self.label_2 = QtWidgets.QLabel(self.widget) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.lineEditPassword = QtWidgets.QLineEdit(self.widget) + self.lineEditPassword.setEchoMode(QtWidgets.QLineEdit.Password) + self.lineEditPassword.setObjectName("lineEditPassword") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lineEditPassword) + self.label_3 = QtWidgets.QLabel(self.widget) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.labelServer = QtWidgets.QLabel(self.widget) + self.labelServer.setText("") + self.labelServer.setObjectName("labelServer") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.labelServer) + self.verticalLayout.addWidget(self.widget) + spacerItem = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout.addItem(spacerItem) + self.widget_2 = QtWidgets.QWidget(login) + self.widget_2.setObjectName("widget_2") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_2) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.checkBoxRememberMe = QtWidgets.QCheckBox(self.widget_2) + self.checkBoxRememberMe.setObjectName("checkBoxRememberMe") + self.horizontalLayout.addWidget(self.checkBoxRememberMe) + self.buttonBox = QtWidgets.QDialogButtonBox(self.widget_2) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.horizontalLayout.addWidget(self.buttonBox) + self.verticalLayout.addWidget(self.widget_2) + + self.retranslateUi(login) + self.buttonBox.accepted.connect(login.accept) # type: ignore + self.buttonBox.rejected.connect(login.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(login)
+ + +
+[docs] + def retranslateUi(self, login): + _translate = QtCore.QCoreApplication.translate + login.setWindowTitle(_translate("login", "Log In")) + self.label.setText(_translate("login", "Username")) + self.label_2.setText(_translate("login", "Password")) + self.label_3.setText(_translate("login", "Server")) + self.checkBoxRememberMe.setText(_translate("login", "remember me"))
+
+ + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + login = QtWidgets.QDialog() + ui = Ui_login() + ui.setupUi(login) + login.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_splash.html b/_modules/iblrig/gui/ui_splash.html new file mode 100644 index 000000000..518ce6269 --- /dev/null +++ b/_modules/iblrig/gui/ui_splash.html @@ -0,0 +1,276 @@ + + + + + + iblrig.gui.ui_splash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_splash

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_splash.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_splash(object): +
+[docs] + def setupUi(self, splash): + splash.setObjectName("splash") + splash.setWindowModality(QtCore.Qt.ApplicationModal) + splash.resize(350, 400) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(splash.sizePolicy().hasHeightForWidth()) + splash.setSizePolicy(sizePolicy) + splash.setMinimumSize(QtCore.QSize(350, 400)) + splash.setMaximumSize(QtCore.QSize(350, 400)) + self.verticalLayout = QtWidgets.QVBoxLayout(splash) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setSpacing(0) + self.verticalLayout.setObjectName("verticalLayout") + self.containerWidget = QtWidgets.QWidget(splash) + self.containerWidget.setStyleSheet("QWidget#containerWidget { background-color: qradialgradient(spread:pad, cx:0.5, cy:0.5, radius:0.5, fx:0.5, fy:0.5, stop:0 rgba(255, 255, 255, 0), stop:1 rgba(200, 200, 200, 255)) };") + self.containerWidget.setObjectName("containerWidget") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.containerWidget) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.horizontalWidget = QtWidgets.QWidget(self.containerWidget) + self.horizontalWidget.setObjectName("horizontalWidget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalWidget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setSpacing(0) + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.widgetLogo = QtWidgets.QWidget(self.horizontalWidget) + self.widgetLogo.setMinimumSize(QtCore.QSize(250, 240)) + self.widgetLogo.setMaximumSize(QtCore.QSize(250, 16777215)) + self.widgetLogo.setStyleSheet("") + self.widgetLogo.setObjectName("widgetLogo") + self.logo = QtWidgets.QLabel(self.widgetLogo) + self.logo.setGeometry(QtCore.QRect(50, 100, 150, 150)) + self.logo.setStyleSheet("") + self.logo.setPixmap(QtGui.QPixmap(":/images/logo_ibl")) + self.logo.setScaledContents(True) + self.logo.setObjectName("logo") + self.hat = QtWidgets.QLabel(self.widgetLogo) + self.hat.setGeometry(QtCore.QRect(0, 50, 150, 150)) + self.hat.setPixmap(QtGui.QPixmap(":/images/iblrig_logo")) + self.hat.setScaledContents(True) + self.hat.setObjectName("hat") + self.horizontalLayout.addWidget(self.widgetLogo) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.verticalLayout_3.addWidget(self.horizontalWidget) + spacerItem2 = QtWidgets.QSpacerItem(20, 30, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_3.addItem(spacerItem2) + self.widgetText = QtWidgets.QWidget(self.containerWidget) + self.widgetText.setObjectName("widgetText") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.widgetText) + self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.labelRig = QtWidgets.QLabel(self.widgetText) + font = QtGui.QFont() + font.setFamily("Arial") + font.setPointSize(15) + font.setBold(True) + font.setWeight(75) + self.labelRig.setFont(font) + self.labelRig.setAlignment(QtCore.Qt.AlignCenter) + self.labelRig.setObjectName("labelRig") + self.verticalLayout_4.addWidget(self.labelRig) + self.labelVersion = QtWidgets.QLabel(self.widgetText) + self.labelVersion.setAlignment(QtCore.Qt.AlignCenter) + self.labelVersion.setObjectName("labelVersion") + self.verticalLayout_4.addWidget(self.labelVersion) + self.verticalLayout_3.addWidget(self.widgetText) + spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_3.addItem(spacerItem3) + self.horizontalWidget1 = QtWidgets.QWidget(self.containerWidget) + self.horizontalWidget1.setAutoFillBackground(False) + self.horizontalWidget1.setStyleSheet("background-color: rgb(255, 255, 255);") + self.horizontalWidget1.setObjectName("horizontalWidget1") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.horizontalWidget1) + self.horizontalLayout_2.setContentsMargins(9, 2, 9, 2) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.labelStatus = QtWidgets.QLabel(self.horizontalWidget1) + self.labelStatus.setObjectName("labelStatus") + self.horizontalLayout_2.addWidget(self.labelStatus) + self.verticalLayout_3.addWidget(self.horizontalWidget1) + spacerItem4 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_3.addItem(spacerItem4) + self.labelCopyright = QtWidgets.QLabel(self.containerWidget) + self.labelCopyright.setAlignment(QtCore.Qt.AlignCenter) + self.labelCopyright.setObjectName("labelCopyright") + self.verticalLayout_3.addWidget(self.labelCopyright) + spacerItem5 = QtWidgets.QSpacerItem(20, 5, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_3.addItem(spacerItem5) + self.verticalLayout.addWidget(self.containerWidget) + + self.retranslateUi(splash) + QtCore.QMetaObject.connectSlotsByName(splash)
+ + +
+[docs] + def retranslateUi(self, splash): + _translate = QtCore.QCoreApplication.translate + splash.setWindowTitle(_translate("splash", "Dialog")) + self.labelRig.setText(_translate("splash", "IBLRIG Wizard")) + self.labelVersion.setText(_translate("splash", "v8.13.0")) + self.labelStatus.setText(_translate("splash", "Status")) + self.labelCopyright.setText(_translate("splash", "© 2024, International Brain Laboratory"))
+
+ +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + splash = QtWidgets.QDialog() + ui = Ui_splash() + ui.setupUi(splash) + splash.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_tab_about.html b/_modules/iblrig/gui/ui_tab_about.html new file mode 100644 index 000000000..a446489b9 --- /dev/null +++ b/_modules/iblrig/gui/ui_tab_about.html @@ -0,0 +1,248 @@ + + + + + + iblrig.gui.ui_tab_about — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_tab_about

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig/gui/ui_tab_about.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.9
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_TabAbout(object): +
+[docs] + def setupUi(self, TabAbout): + TabAbout.setObjectName("TabAbout") + TabAbout.resize(498, 559) + self.gridLayout = QtWidgets.QGridLayout(TabAbout) + self.gridLayout.setObjectName("gridLayout") + spacerItem = QtWidgets.QSpacerItem(87, 45, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem, 0, 2, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(186, 87, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 1, 0, 1, 2) + self.uiLabelLogo = QtWidgets.QLabel(TabAbout) + self.uiLabelLogo.setMaximumSize(QtCore.QSize(90, 90)) + self.uiLabelLogo.setText("") + self.uiLabelLogo.setPixmap(QtGui.QPixmap(":/images/iblrig_logo")) + self.uiLabelLogo.setScaledContents(True) + self.uiLabelLogo.setObjectName("uiLabelLogo") + self.gridLayout.addWidget(self.uiLabelLogo, 1, 2, 1, 1) + spacerItem2 = QtWidgets.QSpacerItem(186, 87, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem2, 1, 3, 1, 2) + self.uiLabelCopyright = QtWidgets.QLabel(TabAbout) + self.uiLabelCopyright.setTextFormat(QtCore.Qt.MarkdownText) + self.uiLabelCopyright.setAlignment(QtCore.Qt.AlignCenter) + self.uiLabelCopyright.setObjectName("uiLabelCopyright") + self.gridLayout.addWidget(self.uiLabelCopyright, 2, 0, 1, 5) + spacerItem3 = QtWidgets.QSpacerItem(407, 46, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem3, 3, 0, 1, 5) + spacerItem4 = QtWidgets.QSpacerItem(145, 157, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem4, 4, 0, 4, 1) + self.commandLinkButtonGitHub = QtWidgets.QCommandLinkButton(TabAbout) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/images/github"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.commandLinkButtonGitHub.setIcon(icon) + self.commandLinkButtonGitHub.setObjectName("commandLinkButtonGitHub") + self.gridLayout.addWidget(self.commandLinkButtonGitHub, 4, 1, 1, 3) + spacerItem5 = QtWidgets.QSpacerItem(145, 157, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem5, 4, 4, 4, 1) + self.commandLinkButtonDoc = QtWidgets.QCommandLinkButton(TabAbout) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/images/help"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.commandLinkButtonDoc.setIcon(icon1) + self.commandLinkButtonDoc.setObjectName("commandLinkButtonDoc") + self.gridLayout.addWidget(self.commandLinkButtonDoc, 5, 1, 1, 3) + self.commandLinkButtonDiscussion = QtWidgets.QCommandLinkButton(TabAbout) + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/images/discussion"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.commandLinkButtonDiscussion.setIcon(icon2) + self.commandLinkButtonDiscussion.setObjectName("commandLinkButtonDiscussion") + self.gridLayout.addWidget(self.commandLinkButtonDiscussion, 6, 1, 1, 3) + self.commandLinkButtonIssues = QtWidgets.QCommandLinkButton(TabAbout) + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/images/bug"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.commandLinkButtonIssues.setIcon(icon3) + self.commandLinkButtonIssues.setObjectName("commandLinkButtonIssues") + self.gridLayout.addWidget(self.commandLinkButtonIssues, 7, 1, 1, 3) + spacerItem6 = QtWidgets.QSpacerItem(407, 74, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem6, 8, 0, 1, 5) + self.uiLabelAnyDesk = QtWidgets.QLabel(TabAbout) + self.uiLabelAnyDesk.setText("") + self.uiLabelAnyDesk.setAlignment(QtCore.Qt.AlignCenter) + self.uiLabelAnyDesk.setObjectName("uiLabelAnyDesk") + self.gridLayout.addWidget(self.uiLabelAnyDesk, 9, 0, 1, 5) + + self.retranslateUi(TabAbout) + QtCore.QMetaObject.connectSlotsByName(TabAbout)
+ + +
+[docs] + def retranslateUi(self, TabAbout): + _translate = QtCore.QCoreApplication.translate + TabAbout.setWindowTitle(_translate("TabAbout", "Form")) + self.uiLabelCopyright.setText(_translate("TabAbout", "**IBLRIG v8.13.0**\n" +"\n" +"© 2024, International Brain Laboratory")) + self.commandLinkButtonGitHub.setStatusTip(_translate("TabAbout", "Click to open the IBLRIG GitHub repository")) + self.commandLinkButtonGitHub.setText(_translate("TabAbout", "&GitHub")) + self.commandLinkButtonDoc.setStatusTip(_translate("TabAbout", "Click to open the IBLRIG documentation")) + self.commandLinkButtonDoc.setText(_translate("TabAbout", "&Documentation")) + self.commandLinkButtonDiscussion.setStatusTip(_translate("TabAbout", "Click to open the IBLRIG discussion board")) + self.commandLinkButtonDiscussion.setText(_translate("TabAbout", "Discussion &Board")) + self.commandLinkButtonIssues.setStatusTip(_translate("TabAbout", "Click to open the IBLRIG issue tracker")) + self.commandLinkButtonIssues.setText(_translate("TabAbout", "&Issue Tracker"))
+
+ +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + TabAbout = QtWidgets.QWidget() + ui = Ui_TabAbout() + ui.setupUi(TabAbout) + TabAbout.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_tab_data.html b/_modules/iblrig/gui/ui_tab_data.html new file mode 100644 index 000000000..39dd0adc5 --- /dev/null +++ b/_modules/iblrig/gui/ui_tab_data.html @@ -0,0 +1,216 @@ + + + + + + iblrig.gui.ui_tab_data — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_tab_data

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_tab_data.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_TabData(object): +
+[docs] + def setupUi(self, TabData): + TabData.setObjectName("TabData") + TabData.resize(776, 678) + self.verticalLayout = QtWidgets.QVBoxLayout(TabData) + self.verticalLayout.setObjectName("verticalLayout") + self.tableView = QtWidgets.QTableView(TabData) + self.tableView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.tableView.setTabKeyNavigation(False) + self.tableView.setProperty("showDropIndicator", False) + self.tableView.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.tableView.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel) + self.tableView.setShowGrid(False) + self.tableView.setSortingEnabled(True) + self.tableView.setWordWrap(False) + self.tableView.setObjectName("tableView") + self.tableView.horizontalHeader().setCascadingSectionResizes(True) + self.tableView.horizontalHeader().setHighlightSections(False) + self.tableView.verticalHeader().setVisible(False) + self.verticalLayout.addWidget(self.tableView) + self.horizontalWidget = QtWidgets.QWidget(TabData) + self.horizontalWidget.setObjectName("horizontalWidget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalWidget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.lineEditFilter = QtWidgets.QLineEdit(self.horizontalWidget) + self.lineEditFilter.setObjectName("lineEditFilter") + self.horizontalLayout.addWidget(self.lineEditFilter) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.pushButtonUpdate = QtWidgets.QPushButton(self.horizontalWidget) + self.pushButtonUpdate.setObjectName("pushButtonUpdate") + self.horizontalLayout.addWidget(self.pushButtonUpdate) + self.horizontalLayout.setStretch(1, 1) + self.verticalLayout.addWidget(self.horizontalWidget) + + self.retranslateUi(TabData) + QtCore.QMetaObject.connectSlotsByName(TabData)
+ + +
+[docs] + def retranslateUi(self, TabData): + _translate = QtCore.QCoreApplication.translate + TabData.setWindowTitle(_translate("TabData", "Form")) + self.tableView.setStatusTip(_translate("TabData", "Double-click a row to open the respective folder")) + self.lineEditFilter.setStatusTip(_translate("TabData", "Filter table by subject")) + self.lineEditFilter.setPlaceholderText(_translate("TabData", "Filter by Subject")) + self.pushButtonUpdate.setStatusTip(_translate("TabData", "Update table")) + self.pushButtonUpdate.setText(_translate("TabData", "Update"))
+
+ + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + TabData = QtWidgets.QWidget() + ui = Ui_TabData() + ui.setupUi(TabData) + TabData.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_tab_docs.html b/_modules/iblrig/gui/ui_tab_docs.html new file mode 100644 index 000000000..a4b626df6 --- /dev/null +++ b/_modules/iblrig/gui/ui_tab_docs.html @@ -0,0 +1,249 @@ + + + + + + iblrig.gui.ui_tab_docs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_tab_docs

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig/gui/ui_tab_docs.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.9
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_TabDocs(object): +
+[docs] + def setupUi(self, TabDocs): + TabDocs.setObjectName("TabDocs") + TabDocs.resize(706, 695) + self.verticalLayout = QtWidgets.QVBoxLayout(TabDocs) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.verticalLayout.setObjectName("verticalLayout") + self.webEngineView = QtWebEngineWidgets.QWebEngineView(TabDocs) + self.webEngineView.setContextMenuPolicy(QtCore.Qt.NoContextMenu) + self.webEngineView.setAcceptDrops(False) + self.webEngineView.setProperty("url", QtCore.QUrl("https://int-brain-lab.github.io/iblrig/")) + self.webEngineView.setProperty("zoomFactor", 0.9) + self.webEngineView.setObjectName("webEngineView") + self.verticalLayout.addWidget(self.webEngineView) + self.line = QtWidgets.QFrame(TabDocs) + self.line.setFrameShadow(QtWidgets.QFrame.Sunken) + self.line.setFrameShape(QtWidgets.QFrame.HLine) + self.line.setObjectName("line") + self.verticalLayout.addWidget(self.line) + self.frame = QtWidgets.QFrame(TabDocs) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth()) + self.frame.setSizePolicy(sizePolicy) + self.frame.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame.setLineWidth(0) + self.frame.setObjectName("frame") + self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.frame) + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.uiPushWebBack = QtWidgets.QPushButton(self.frame) + self.uiPushWebBack.setEnabled(False) + self.uiPushWebBack.setMaximumSize(QtCore.QSize(24, 16777215)) + self.uiPushWebBack.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/images/previous"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushWebBack.setIcon(icon) + self.uiPushWebBack.setObjectName("uiPushWebBack") + self.horizontalLayout_5.addWidget(self.uiPushWebBack) + self.uiPushWebForward = QtWidgets.QPushButton(self.frame) + self.uiPushWebForward.setEnabled(False) + self.uiPushWebForward.setMaximumSize(QtCore.QSize(24, 16777215)) + self.uiPushWebForward.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/images/next"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushWebForward.setIcon(icon1) + self.uiPushWebForward.setObjectName("uiPushWebForward") + self.horizontalLayout_5.addWidget(self.uiPushWebForward) + self.uiPushWebHome = QtWidgets.QPushButton(self.frame) + self.uiPushWebHome.setMaximumSize(QtCore.QSize(24, 16777215)) + self.uiPushWebHome.setText("") + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/images/home"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushWebHome.setIcon(icon2) + self.uiPushWebHome.setIconSize(QtCore.QSize(16, 16)) + self.uiPushWebHome.setObjectName("uiPushWebHome") + self.horizontalLayout_5.addWidget(self.uiPushWebHome) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_5.addItem(spacerItem) + self.uiPushWebBrowser = QtWidgets.QPushButton(self.frame) + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/images/globe"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushWebBrowser.setIcon(icon3) + self.uiPushWebBrowser.setObjectName("uiPushWebBrowser") + self.horizontalLayout_5.addWidget(self.uiPushWebBrowser) + self.verticalLayout.addWidget(self.frame) + self.verticalLayout.setStretch(0, 1) + + self.retranslateUi(TabDocs) + QtCore.QMetaObject.connectSlotsByName(TabDocs)
+ + +
+[docs] + def retranslateUi(self, TabDocs): + _translate = QtCore.QCoreApplication.translate + TabDocs.setWindowTitle(_translate("TabDocs", "Form")) + self.uiPushWebBack.setStatusTip(_translate("TabDocs", "Click to go back")) + self.uiPushWebForward.setStatusTip(_translate("TabDocs", "Click to go forward")) + self.uiPushWebHome.setStatusTip(_translate("TabDocs", "Click to go to home page")) + self.uiPushWebBrowser.setStatusTip(_translate("TabDocs", "Click to open the current page in your web browser")) + self.uiPushWebBrowser.setText(_translate("TabDocs", " Open in Browser"))
+
+ +from PyQt5 import QtWebEngineWidgets +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + TabDocs = QtWidgets.QWidget() + ui = Ui_TabDocs() + ui.setupUi(TabDocs) + TabDocs.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_tab_log.html b/_modules/iblrig/gui/ui_tab_log.html new file mode 100644 index 000000000..13109446b --- /dev/null +++ b/_modules/iblrig/gui/ui_tab_log.html @@ -0,0 +1,220 @@ + + + + + + iblrig.gui.ui_tab_log — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_tab_log

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_tab_log.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_TabLog(object): +
+[docs] + def setupUi(self, TabLog): + TabLog.setObjectName("TabLog") + TabLog.resize(607, 766) + self.verticalLayout = QtWidgets.QVBoxLayout(TabLog) + self.verticalLayout.setObjectName("verticalLayout") + self.plainTextEditLog = QtWidgets.QPlainTextEdit(TabLog) + self.plainTextEditLog.setStyleSheet("QPlainTextEdit {background-color: rgb(0, 0, 0)};") + self.plainTextEditLog.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap) + self.plainTextEditLog.setReadOnly(True) + self.plainTextEditLog.setObjectName("plainTextEditLog") + self.verticalLayout.addWidget(self.plainTextEditLog) + self.widget = QtWidgets.QWidget(TabLog) + self.widget.setObjectName("widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.labelFontSize = QtWidgets.QLabel(self.widget) + self.labelFontSize.setObjectName("labelFontSize") + self.horizontalLayout.addWidget(self.labelFontSize) + self.spinBoxFontSize = QtWidgets.QSpinBox(self.widget) + self.spinBoxFontSize.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.spinBoxFontSize.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus) + self.spinBoxFontSize.setAccelerated(False) + self.spinBoxFontSize.setMinimum(7) + self.spinBoxFontSize.setMaximum(99) + self.spinBoxFontSize.setProperty("value", 11) + self.spinBoxFontSize.setObjectName("spinBoxFontSize") + self.horizontalLayout.addWidget(self.spinBoxFontSize) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.pushButtonClipboard = QtWidgets.QPushButton(self.widget) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/images/clipboard"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pushButtonClipboard.setIcon(icon) + self.pushButtonClipboard.setObjectName("pushButtonClipboard") + self.horizontalLayout.addWidget(self.pushButtonClipboard) + self.verticalLayout.addWidget(self.widget) + self.labelFontSize.setBuddy(self.spinBoxFontSize) + + self.retranslateUi(TabLog) + QtCore.QMetaObject.connectSlotsByName(TabLog)
+ + +
+[docs] + def retranslateUi(self, TabLog): + _translate = QtCore.QCoreApplication.translate + TabLog.setWindowTitle(_translate("TabLog", "Form")) + self.labelFontSize.setStatusTip(_translate("TabLog", "Set the log\'s font size")) + self.labelFontSize.setText(_translate("TabLog", "&Font Size")) + self.spinBoxFontSize.setStatusTip(_translate("TabLog", "Set the log\'s font size")) + self.pushButtonClipboard.setStatusTip(_translate("TabLog", "Copy log to clipboard")) + self.pushButtonClipboard.setText(_translate("TabLog", " &Copy"))
+
+ +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + TabLog = QtWidgets.QWidget() + ui = Ui_TabLog() + ui.setupUi(TabLog) + TabLog.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_tab_session.html b/_modules/iblrig/gui/ui_tab_session.html new file mode 100644 index 000000000..c5b98fb01 --- /dev/null +++ b/_modules/iblrig/gui/ui_tab_session.html @@ -0,0 +1,494 @@ + + + + + + iblrig.gui.ui_tab_session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_tab_session

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig/gui/ui_tab_session.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.9
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_tabSession(object): +
+[docs] + def setupUi(self, tabSession): + tabSession.setObjectName("tabSession") + tabSession.resize(346, 636) + self.gridLayout = QtWidgets.QGridLayout(tabSession) + self.gridLayout.setObjectName("gridLayout") + self.uiGroupParameters = QtWidgets.QGroupBox(tabSession) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiGroupParameters.sizePolicy().hasHeightForWidth()) + self.uiGroupParameters.setSizePolicy(sizePolicy) + self.uiGroupParameters.setObjectName("uiGroupParameters") + self.formLayout = QtWidgets.QFormLayout(self.uiGroupParameters) + self.formLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) + self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(self.uiGroupParameters) + self.label.setObjectName("label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label) + self.frame_3 = QtWidgets.QFrame(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_3.sizePolicy().hasHeightForWidth()) + self.frame_3.setSizePolicy(sizePolicy) + self.frame_3.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_3.setObjectName("frame_3") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_3) + self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.uiComboUser = QtWidgets.QComboBox(self.frame_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(3) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiComboUser.sizePolicy().hasHeightForWidth()) + self.uiComboUser.setSizePolicy(sizePolicy) + self.uiComboUser.setEditable(True) + self.uiComboUser.setObjectName("uiComboUser") + self.horizontalLayout_2.addWidget(self.uiComboUser) + self.uiPushConnect = QtWidgets.QPushButton(self.frame_3) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(2) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPushConnect.sizePolicy().hasHeightForWidth()) + self.uiPushConnect.setSizePolicy(sizePolicy) + self.uiPushConnect.setMaximumSize(QtCore.QSize(150, 16777215)) + self.uiPushConnect.setToolTip("") + self.uiPushConnect.setObjectName("uiPushConnect") + self.horizontalLayout_2.addWidget(self.uiPushConnect) + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.frame_3) + self.label_2 = QtWidgets.QLabel(self.uiGroupParameters) + self.label_2.setObjectName("label_2") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_2) + self.frame_2 = QtWidgets.QFrame(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) + self.frame_2.setSizePolicy(sizePolicy) + self.frame_2.setFrameShape(QtWidgets.QFrame.NoFrame) + self.frame_2.setObjectName("frame_2") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_2) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.uiComboSubject = QtWidgets.QComboBox(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(3) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiComboSubject.sizePolicy().hasHeightForWidth()) + self.uiComboSubject.setSizePolicy(sizePolicy) + self.uiComboSubject.setMinimumSize(QtCore.QSize(0, 0)) + self.uiComboSubject.setObjectName("uiComboSubject") + self.horizontalLayout.addWidget(self.uiComboSubject) + self.lineEditSubject = QtWidgets.QLineEdit(self.frame_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(2) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEditSubject.sizePolicy().hasHeightForWidth()) + self.lineEditSubject.setSizePolicy(sizePolicy) + self.lineEditSubject.setLayoutDirection(QtCore.Qt.LeftToRight) + self.lineEditSubject.setObjectName("lineEditSubject") + self.horizontalLayout.addWidget(self.lineEditSubject) + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.frame_2) + self.label_4 = QtWidgets.QLabel(self.uiGroupParameters) + self.label_4.setObjectName("label_4") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_4) + self.uiComboTask = QtWidgets.QComboBox(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiComboTask.sizePolicy().hasHeightForWidth()) + self.uiComboTask.setSizePolicy(sizePolicy) + self.uiComboTask.setMinimumSize(QtCore.QSize(0, 0)) + self.uiComboTask.setObjectName("uiComboTask") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.uiComboTask) + self.label_3 = QtWidgets.QLabel(self.uiGroupParameters) + self.label_3.setObjectName("label_3") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3) + self.uiListProjects = QtWidgets.QListView(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiListProjects.sizePolicy().hasHeightForWidth()) + self.uiListProjects.setSizePolicy(sizePolicy) + self.uiListProjects.setMaximumSize(QtCore.QSize(16777215, 80)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, brush) + self.uiListProjects.setPalette(palette) + self.uiListProjects.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.uiListProjects.setFocusPolicy(QtCore.Qt.TabFocus) + self.uiListProjects.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.uiListProjects.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.uiListProjects.setObjectName("uiListProjects") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiListProjects) + self.label_5 = QtWidgets.QLabel(self.uiGroupParameters) + self.label_5.setObjectName("label_5") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_5) + self.uiListProcedures = QtWidgets.QListView(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiListProcedures.sizePolicy().hasHeightForWidth()) + self.uiListProcedures.setSizePolicy(sizePolicy) + self.uiListProcedures.setMaximumSize(QtCore.QSize(16777215, 80)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, brush) + self.uiListProcedures.setPalette(palette) + self.uiListProcedures.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.uiListProcedures.setFocusPolicy(QtCore.Qt.TabFocus) + self.uiListProcedures.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.uiListProcedures.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.uiListProcedures.setObjectName("uiListProcedures") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiListProcedures) + self.gridLayout.addWidget(self.uiGroupParameters, 0, 0, 1, 2) + self.uiGroupTaskParameters = QtWidgets.QGroupBox(tabSession) + self.uiGroupTaskParameters.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiGroupTaskParameters.sizePolicy().hasHeightForWidth()) + self.uiGroupTaskParameters.setSizePolicy(sizePolicy) + self.uiGroupTaskParameters.setMinimumSize(QtCore.QSize(0, 0)) + self.uiGroupTaskParameters.setObjectName("uiGroupTaskParameters") + self.formLayout_3 = QtWidgets.QFormLayout(self.uiGroupTaskParameters) + self.formLayout_3.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_3.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout_3.setObjectName("formLayout_3") + self.gridLayout.addWidget(self.uiGroupTaskParameters, 1, 0, 1, 2) + self.uiGroupSessionControl = QtWidgets.QGroupBox(tabSession) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiGroupSessionControl.sizePolicy().hasHeightForWidth()) + self.uiGroupSessionControl.setSizePolicy(sizePolicy) + self.uiGroupSessionControl.setObjectName("uiGroupSessionControl") + self.gridLayout_2 = QtWidgets.QGridLayout(self.uiGroupSessionControl) + self.gridLayout_2.setObjectName("gridLayout_2") + self.uiPushPause = QtWidgets.QPushButton(self.uiGroupSessionControl) + self.uiPushPause.setEnabled(False) + self.uiPushPause.setCheckable(True) + self.uiPushPause.setChecked(False) + self.uiPushPause.setObjectName("uiPushPause") + self.gridLayout_2.addWidget(self.uiPushPause, 2, 1, 1, 1) + self.uiPushStart = QtWidgets.QPushButton(self.uiGroupSessionControl) + self.uiPushStart.setStyleSheet("QPushButton { background-color: red; }") + self.uiPushStart.setObjectName("uiPushStart") + self.gridLayout_2.addWidget(self.uiPushStart, 2, 2, 1, 1) + self.uiCheckAppend = QtWidgets.QCheckBox(self.uiGroupSessionControl) + self.uiCheckAppend.setObjectName("uiCheckAppend") + self.gridLayout_2.addWidget(self.uiCheckAppend, 3, 2, 1, 1) + self.gridLayout.addWidget(self.uiGroupSessionControl, 2, 0, 1, 2) + self.uiGroupTools = QtWidgets.QGroupBox(tabSession) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiGroupTools.sizePolicy().hasHeightForWidth()) + self.uiGroupTools.setSizePolicy(sizePolicy) + self.uiGroupTools.setObjectName("uiGroupTools") + self.gridLayout_3 = QtWidgets.QGridLayout(self.uiGroupTools) + self.gridLayout_3.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.gridLayout_3.setObjectName("gridLayout_3") + self.uiPushFlush = QtWidgets.QPushButton(self.uiGroupTools) + self.uiPushFlush.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPushFlush.sizePolicy().hasHeightForWidth()) + self.uiPushFlush.setSizePolicy(sizePolicy) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/images/flush"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushFlush.setIcon(icon) + self.uiPushFlush.setCheckable(True) + self.uiPushFlush.setObjectName("uiPushFlush") + self.gridLayout_3.addWidget(self.uiPushFlush, 0, 0, 1, 1) + self.uiPushHelp = QtWidgets.QPushButton(self.uiGroupTools) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPushHelp.sizePolicy().hasHeightForWidth()) + self.uiPushHelp.setSizePolicy(sizePolicy) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/images/help"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushHelp.setIcon(icon1) + self.uiPushHelp.setObjectName("uiPushHelp") + self.gridLayout_3.addWidget(self.uiPushHelp, 2, 0, 1, 1) + self.uiPushStatusLED = QtWidgets.QPushButton(self.uiGroupTools) + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/images/status_led"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushStatusLED.setIcon(icon2) + self.uiPushStatusLED.setCheckable(True) + self.uiPushStatusLED.setObjectName("uiPushStatusLED") + self.gridLayout_3.addWidget(self.uiPushStatusLED, 1, 0, 1, 1) + self.gridLayout.addWidget(self.uiGroupTools, 3, 0, 1, 1) + self.uiGroupDiskSpace = QtWidgets.QGroupBox(tabSession) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiGroupDiskSpace.sizePolicy().hasHeightForWidth()) + self.uiGroupDiskSpace.setSizePolicy(sizePolicy) + self.uiGroupDiskSpace.setObjectName("uiGroupDiskSpace") + self.formLayout_2 = QtWidgets.QFormLayout(self.uiGroupDiskSpace) + self.formLayout_2.setObjectName("formLayout_2") + self.uiProgressDiskSpace = QtWidgets.QProgressBar(self.uiGroupDiskSpace) + self.uiProgressDiskSpace.setProperty("value", 24) + self.uiProgressDiskSpace.setInvertedAppearance(False) + self.uiProgressDiskSpace.setTextDirection(QtWidgets.QProgressBar.TopToBottom) + self.uiProgressDiskSpace.setObjectName("uiProgressDiskSpace") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.uiProgressDiskSpace) + self.uiLabelDiskIblrig = QtWidgets.QLabel(self.uiGroupDiskSpace) + self.uiLabelDiskIblrig.setObjectName("uiLabelDiskIblrig") + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.uiLabelDiskIblrig) + self.uiLabelDiskIblrigValue = QtWidgets.QLabel(self.uiGroupDiskSpace) + self.uiLabelDiskIblrigValue.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.uiLabelDiskIblrigValue.setObjectName("uiLabelDiskIblrigValue") + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.uiLabelDiskIblrigValue) + self.uiLabelDiskAvailable = QtWidgets.QLabel(self.uiGroupDiskSpace) + self.uiLabelDiskAvailable.setObjectName("uiLabelDiskAvailable") + self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.uiLabelDiskAvailable) + self.uiLabelDiskAvailableValue = QtWidgets.QLabel(self.uiGroupDiskSpace) + self.uiLabelDiskAvailableValue.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.uiLabelDiskAvailableValue.setObjectName("uiLabelDiskAvailableValue") + self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiLabelDiskAvailableValue) + spacerItem = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.formLayout_2.setItem(0, QtWidgets.QFormLayout.SpanningRole, spacerItem) + spacerItem1 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.formLayout_2.setItem(4, QtWidgets.QFormLayout.SpanningRole, spacerItem1) + self.gridLayout.addWidget(self.uiGroupDiskSpace, 3, 1, 1, 1) + + self.retranslateUi(tabSession) + QtCore.QMetaObject.connectSlotsByName(tabSession)
+ + +
+[docs] + def retranslateUi(self, tabSession): + _translate = QtCore.QCoreApplication.translate + tabSession.setWindowTitle(_translate("tabSession", "Form")) + self.uiGroupParameters.setTitle(_translate("tabSession", "General Parameters")) + self.label.setText(_translate("tabSession", "Alyx User")) + self.uiComboUser.setStatusTip(_translate("tabSession", "enter or select your Alyx username")) + self.uiPushConnect.setStatusTip(_translate("tabSession", "connect to Alyx")) + self.uiPushConnect.setText(_translate("tabSession", "Connect")) + self.label_2.setText(_translate("tabSession", "Subject")) + self.uiComboSubject.setStatusTip(_translate("tabSession", "choose a subject")) + self.lineEditSubject.setStatusTip(_translate("tabSession", "filter displayed subjects by name")) + self.lineEditSubject.setPlaceholderText(_translate("tabSession", "Filter")) + self.label_4.setText(_translate("tabSession", "Task")) + self.uiComboTask.setStatusTip(_translate("tabSession", "choose a task for the session")) + self.label_3.setText(_translate("tabSession", "Project")) + self.uiListProjects.setStatusTip(_translate("tabSession", "select one or several projects for the session (mandatory)")) + self.label_5.setText(_translate("tabSession", "Procedure")) + self.uiListProcedures.setStatusTip(_translate("tabSession", "select one or several procedures for the session (mandatory)")) + self.uiGroupTaskParameters.setTitle(_translate("tabSession", "Task Specific Parameters")) + self.uiGroupSessionControl.setTitle(_translate("tabSession", "Session Control")) + self.uiPushPause.setStatusTip(_translate("tabSession", "pause the session after the current trial")) + self.uiPushPause.setText(_translate("tabSession", "Pause")) + self.uiPushStart.setStatusTip(_translate("tabSession", "start the session")) + self.uiPushStart.setText(_translate("tabSession", "Start")) + self.uiCheckAppend.setStatusTip(_translate("tabSession", "append to previous session")) + self.uiCheckAppend.setText(_translate("tabSession", "Append")) + self.uiGroupTools.setTitle(_translate("tabSession", "Tools")) + self.uiPushFlush.setStatusTip(_translate("tabSession", "flush the valve")) + self.uiPushFlush.setText(_translate("tabSession", " Flush Valve")) + self.uiPushHelp.setStatusTip(_translate("tabSession", "open the iblrig documentation in your browser")) + self.uiPushHelp.setText(_translate("tabSession", " Help!")) + self.uiPushStatusLED.setStatusTip(_translate("tabSession", "toggle the Bpod Status LED (always off during sessions)")) + self.uiPushStatusLED.setText(_translate("tabSession", " Status LED")) + self.uiGroupDiskSpace.setTitle(_translate("tabSession", "Disk Usage")) + self.uiLabelDiskIblrig.setText(_translate("tabSession", "IBL Rig Data:")) + self.uiLabelDiskIblrigValue.setText(_translate("tabSession", "1.2 GB")) + self.uiLabelDiskAvailable.setText(_translate("tabSession", "Available Space:")) + self.uiLabelDiskAvailableValue.setText(_translate("tabSession", "80.3 GB"))
+
+ +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + tabSession = QtWidgets.QWidget() + ui = Ui_tabSession() + ui.setupUi(tabSession) + tabSession.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_update.html b/_modules/iblrig/gui/ui_update.html new file mode 100644 index 000000000..64199c216 --- /dev/null +++ b/_modules/iblrig/gui/ui_update.html @@ -0,0 +1,259 @@ + + + + + + iblrig.gui.ui_update — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_update

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_update.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_update(object): +
+[docs] + def setupUi(self, update): + update.setObjectName("update") + update.resize(451, 496) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(update.sizePolicy().hasHeightForWidth()) + update.setSizePolicy(sizePolicy) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("iblrig\\gui\\wizard.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + update.setWindowIcon(icon) + update.setModal(True) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(update) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.uiLayoutLogo = QtWidgets.QVBoxLayout() + self.uiLayoutLogo.setContentsMargins(-1, -1, 6, -1) + self.uiLayoutLogo.setObjectName("uiLayoutLogo") + self.uiLabelLogo = QtWidgets.QLabel(update) + self.uiLabelLogo.setMaximumSize(QtCore.QSize(64, 64)) + self.uiLabelLogo.setText("") + self.uiLabelLogo.setPixmap(QtGui.QPixmap(":/images/iblrig_logo")) + self.uiLabelLogo.setScaledContents(True) + self.uiLabelLogo.setObjectName("uiLabelLogo") + self.uiLayoutLogo.addWidget(self.uiLabelLogo) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.uiLayoutLogo.addItem(spacerItem) + self.horizontalLayout_2.addLayout(self.uiLayoutLogo) + self.uiLayoutRight = QtWidgets.QVBoxLayout() + self.uiLayoutRight.setObjectName("uiLayoutRight") + self.uiLabelHeader = QtWidgets.QLabel(update) + self.uiLabelHeader.setObjectName("uiLabelHeader") + self.uiLayoutRight.addWidget(self.uiLabelHeader) + self.uiTextBrowserChanges = QtWidgets.QTextBrowser(update) + self.uiTextBrowserChanges.setSizeIncrement(QtCore.QSize(0, 0)) + self.uiTextBrowserChanges.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.uiTextBrowserChanges.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.uiTextBrowserChanges.setMarkdown("") + self.uiTextBrowserChanges.setTextInteractionFlags(QtCore.Qt.NoTextInteraction) + self.uiTextBrowserChanges.setObjectName("uiTextBrowserChanges") + self.uiLayoutRight.addWidget(self.uiTextBrowserChanges) + self.uiLabelFooter = QtWidgets.QLabel(update) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiLabelFooter.sizePolicy().hasHeightForWidth()) + self.uiLabelFooter.setSizePolicy(sizePolicy) + self.uiLabelFooter.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) + self.uiLabelFooter.setWordWrap(True) + self.uiLabelFooter.setObjectName("uiLabelFooter") + self.uiLayoutRight.addWidget(self.uiLabelFooter) + spacerItem1 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.uiLayoutRight.addItem(spacerItem1) + self.plainTextEdit = QtWidgets.QPlainTextEdit(update) + self.plainTextEdit.setMaximumSize(QtCore.QSize(16777215, 37)) + self.plainTextEdit.setStyleSheet("background-color: rgb(1, 36, 86);\n" +"color: rgb(255, 255, 255);") + self.plainTextEdit.setReadOnly(True) + self.plainTextEdit.setObjectName("plainTextEdit") + self.uiLayoutRight.addWidget(self.plainTextEdit) + spacerItem2 = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.uiLayoutRight.addItem(spacerItem2) + self.uiLine = QtWidgets.QFrame(update) + self.uiLine.setFrameShape(QtWidgets.QFrame.HLine) + self.uiLine.setFrameShadow(QtWidgets.QFrame.Sunken) + self.uiLine.setObjectName("uiLine") + self.uiLayoutRight.addWidget(self.uiLine) + self.uiLayoutButton = QtWidgets.QHBoxLayout() + self.uiLayoutButton.setObjectName("uiLayoutButton") + spacerItem3 = QtWidgets.QSpacerItem(1, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.uiLayoutButton.addItem(spacerItem3) + self.uiPushButtonOK = QtWidgets.QPushButton(update) + self.uiPushButtonOK.setObjectName("uiPushButtonOK") + self.uiLayoutButton.addWidget(self.uiPushButtonOK) + self.uiLayoutRight.addLayout(self.uiLayoutButton) + self.horizontalLayout_2.addLayout(self.uiLayoutRight) + self.horizontalLayout_2.setStretch(1, 100) + + self.retranslateUi(update) + self.uiPushButtonOK.released.connect(update.close) # type: ignore + QtCore.QMetaObject.connectSlotsByName(update)
+ + +
+[docs] + def retranslateUi(self, update): + _translate = QtCore.QCoreApplication.translate + update.setWindowTitle(_translate("update", "Update Notice")) + self.uiLabelHeader.setText(_translate("update", "Update Available!")) + self.uiLabelFooter.setText(_translate("update", "To update, close IBL Rig Wizard and run the following commands within the iblrigv8 Python environment:")) + self.plainTextEdit.setPlainText(_translate("update", "git pull\n" +"pip install --upgrade -e .")) + self.uiPushButtonOK.setText(_translate("update", "OK"))
+
+ +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + update = QtWidgets.QDialog() + ui = Ui_update() + ui.setupUi(update) + update.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_validation.html b/_modules/iblrig/gui/ui_validation.html new file mode 100644 index 000000000..036c74525 --- /dev/null +++ b/_modules/iblrig/gui/ui_validation.html @@ -0,0 +1,210 @@ + + + + + + iblrig.gui.ui_validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_validation

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_validation.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_validation(object): +
+[docs] + def setupUi(self, validation): + validation.setObjectName("validation") + validation.setWindowModality(QtCore.Qt.ApplicationModal) + validation.resize(500, 357) + self.verticalLayout = QtWidgets.QVBoxLayout(validation) + self.verticalLayout.setObjectName("verticalLayout") + self.treeView = QtWidgets.QTreeView(validation) + self.treeView.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.treeView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.treeView.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.treeView.setProperty("showDropIndicator", False) + self.treeView.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection) + self.treeView.setAllColumnsShowFocus(True) + self.treeView.setWordWrap(True) + self.treeView.setObjectName("treeView") + self.treeView.header().setVisible(False) + self.treeView.header().setStretchLastSection(False) + self.verticalLayout.addWidget(self.treeView) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.pushButtonRerun = QtWidgets.QPushButton(validation) + self.pushButtonRerun.setEnabled(False) + self.pushButtonRerun.setObjectName("pushButtonRerun") + self.horizontalLayout.addWidget(self.pushButtonRerun) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.pushButtonOK = QtWidgets.QPushButton(validation) + self.pushButtonOK.setDefault(True) + self.pushButtonOK.setObjectName("pushButtonOK") + self.horizontalLayout.addWidget(self.pushButtonOK) + self.verticalLayout.addLayout(self.horizontalLayout) + + self.retranslateUi(validation) + QtCore.QMetaObject.connectSlotsByName(validation)
+ + +
+[docs] + def retranslateUi(self, validation): + _translate = QtCore.QCoreApplication.translate + validation.setWindowTitle(_translate("validation", "System Validation")) + self.pushButtonRerun.setText(_translate("validation", "Rerun")) + self.pushButtonOK.setText(_translate("validation", "Close"))
+
+ +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + validation = QtWidgets.QDialog() + ui = Ui_validation() + ui.setupUi(validation) + validation.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_valve.html b/_modules/iblrig/gui/ui_valve.html new file mode 100644 index 000000000..afa32ff4d --- /dev/null +++ b/_modules/iblrig/gui/ui_valve.html @@ -0,0 +1,315 @@ + + + + + + iblrig.gui.ui_valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_valve

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig\gui\ui_valve.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_valve(object): +
+[docs] + def setupUi(self, valve): + valve.setObjectName("valve") + valve.resize(650, 500) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(valve.sizePolicy().hasHeightForWidth()) + valve.setSizePolicy(sizePolicy) + valve.setMinimumSize(QtCore.QSize(650, 500)) + valve.setMaximumSize(QtCore.QSize(650, 500)) + self.verticalLayout = QtWidgets.QVBoxLayout(valve) + self.verticalLayout.setObjectName("verticalLayout") + self.widget = QtWidgets.QWidget(valve) + self.widget.setObjectName("widget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.widget1 = QtWidgets.QWidget(self.widget) + self.widget1.setObjectName("widget1") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget1) + self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.groupBoxScale = QtWidgets.QGroupBox(self.widget1) + self.groupBoxScale.setFlat(False) + self.groupBoxScale.setObjectName("groupBoxScale") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.groupBoxScale) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.lineEditGrams = QtWidgets.QLineEdit(self.groupBoxScale) + self.lineEditGrams.setEnabled(False) + self.lineEditGrams.setMaximumSize(QtCore.QSize(180, 16777215)) + font = QtGui.QFont() + font.setPointSize(30) + self.lineEditGrams.setFont(font) + self.lineEditGrams.setStyleSheet("background-color: rgb(245, 245, 255);") + self.lineEditGrams.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lineEditGrams.setReadOnly(True) + self.lineEditGrams.setObjectName("lineEditGrams") + self.verticalLayout_4.addWidget(self.lineEditGrams) + self.pushButtonTareScale = QtWidgets.QPushButton(self.groupBoxScale) + self.pushButtonTareScale.setEnabled(False) + self.pushButtonTareScale.setObjectName("pushButtonTareScale") + self.verticalLayout_4.addWidget(self.pushButtonTareScale) + self.verticalLayout_3.addWidget(self.groupBoxScale) + self.groupBox_2 = QtWidgets.QGroupBox(self.widget1) + self.groupBox_2.setObjectName("groupBox_2") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.groupBox_2) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.pushButtonToggleValve = QtWidgets.QPushButton(self.groupBox_2) + self.pushButtonToggleValve.setCheckable(True) + self.pushButtonToggleValve.setObjectName("pushButtonToggleValve") + self.horizontalLayout_2.addWidget(self.pushButtonToggleValve) + self.pushButtonPulseValve = QtWidgets.QPushButton(self.groupBox_2) + self.pushButtonPulseValve.setObjectName("pushButtonPulseValve") + self.horizontalLayout_2.addWidget(self.pushButtonPulseValve) + self.verticalLayout_3.addWidget(self.groupBox_2) + self.groupBoxCalibration = QtWidgets.QGroupBox(self.widget1) + self.groupBoxCalibration.setObjectName("groupBoxCalibration") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.groupBoxCalibration) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.labelGuideHead = QtWidgets.QLabel(self.groupBoxCalibration) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.labelGuideHead.setFont(font) + self.labelGuideHead.setObjectName("labelGuideHead") + self.verticalLayout_5.addWidget(self.labelGuideHead) + self.labelGuideText = QtWidgets.QLabel(self.groupBoxCalibration) + self.labelGuideText.setMinimumSize(QtCore.QSize(180, 0)) + self.labelGuideText.setMaximumSize(QtCore.QSize(180, 16777215)) + self.labelGuideText.setTextFormat(QtCore.Qt.MarkdownText) + self.labelGuideText.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) + self.labelGuideText.setWordWrap(True) + self.labelGuideText.setObjectName("labelGuideText") + self.verticalLayout_5.addWidget(self.labelGuideText) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_5.addItem(spacerItem) + self.commandLinkNext = QtWidgets.QCommandLinkButton(self.groupBoxCalibration) + self.commandLinkNext.setEnabled(False) + self.commandLinkNext.setObjectName("commandLinkNext") + self.verticalLayout_5.addWidget(self.commandLinkNext) + self.verticalLayout_3.addWidget(self.groupBoxCalibration) + self.horizontalLayout.addWidget(self.widget1) + self.groupBox = QtWidgets.QGroupBox(self.widget) + self.groupBox.setObjectName("groupBox") + self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.groupBox) + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.frame = QtWidgets.QFrame(self.groupBox) + self.frame.setStyleSheet("background-color: rgb(255, 255, 255);") + self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame.setFrameShadow(QtWidgets.QFrame.Sunken) + self.frame.setObjectName("frame") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.uiPlot = PlotWidget(self.frame) + self.uiPlot.setObjectName("uiPlot") + self.verticalLayout_2.addWidget(self.uiPlot) + self.horizontalLayout_3.addWidget(self.frame) + self.horizontalLayout.addWidget(self.groupBox) + self.horizontalLayout.setStretch(1, 1) + self.verticalLayout.addWidget(self.widget) + self.horizontalFrame = QtWidgets.QFrame(valve) + self.horizontalFrame.setObjectName("horizontalFrame") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.horizontalFrame) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.pushButtonRestart = QtWidgets.QPushButton(self.horizontalFrame) + self.pushButtonRestart.setMinimumSize(QtCore.QSize(0, 30)) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/images/restart"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pushButtonRestart.setIcon(icon) + self.pushButtonRestart.setObjectName("pushButtonRestart") + self.horizontalLayout_4.addWidget(self.pushButtonRestart) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_4.addItem(spacerItem1) + self.pushButtonSave = QtWidgets.QPushButton(self.horizontalFrame) + self.pushButtonSave.setEnabled(False) + self.pushButtonSave.setMinimumSize(QtCore.QSize(0, 30)) + self.pushButtonSave.setObjectName("pushButtonSave") + self.horizontalLayout_4.addWidget(self.pushButtonSave) + self.pushButtonCancel = QtWidgets.QPushButton(self.horizontalFrame) + self.pushButtonCancel.setMinimumSize(QtCore.QSize(0, 30)) + self.pushButtonCancel.setObjectName("pushButtonCancel") + self.horizontalLayout_4.addWidget(self.pushButtonCancel) + self.verticalLayout.addWidget(self.horizontalFrame) + + self.retranslateUi(valve) + QtCore.QMetaObject.connectSlotsByName(valve)
+ + +
+[docs] + def retranslateUi(self, valve): + _translate = QtCore.QCoreApplication.translate + valve.setWindowTitle(_translate("valve", "Valve Calibration")) + self.groupBoxScale.setTitle(_translate("valve", "Scale")) + self.pushButtonTareScale.setText(_translate("valve", "Tare")) + self.groupBox_2.setTitle(_translate("valve", "Valve Controls")) + self.pushButtonToggleValve.setText(_translate("valve", "Flush")) + self.pushButtonPulseValve.setText(_translate("valve", "Pulse")) + self.groupBoxCalibration.setTitle(_translate("valve", "Guided Calibration")) + self.labelGuideHead.setText(_translate("valve", "Heading")) + self.labelGuideText.setText(_translate("valve", "Help string displayed here.")) + self.commandLinkNext.setText(_translate("valve", "Next Step")) + self.groupBox.setTitle(_translate("valve", "Calibration Curve")) + self.pushButtonRestart.setText(_translate("valve", "Start Over")) + self.pushButtonSave.setText(_translate("valve", "Save")) + self.pushButtonCancel.setText(_translate("valve", "Cancel"))
+
+ +from pyqtgraph import PlotWidget +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + valve = QtWidgets.QDialog() + ui = Ui_valve() + ui.setupUi(valve) + valve.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/ui_wizard.html b/_modules/iblrig/gui/ui_wizard.html new file mode 100644 index 000000000..9915f27ec --- /dev/null +++ b/_modules/iblrig/gui/ui_wizard.html @@ -0,0 +1,555 @@ + + + + + + iblrig.gui.ui_wizard — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.ui_wizard

+# -*- coding: utf-8 -*-
+
+# Form implementation generated from reading ui file 'iblrig/gui/ui_wizard.ui'
+#
+# Created by: PyQt5 UI code generator 5.15.10
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again.  Do not edit this file unless you know what you are doing.
+
+
+from PyQt5 import QtCore, QtGui, QtWidgets
+
+
+
+[docs] +class Ui_wizard(object): +
+[docs] + def setupUi(self, wizard): + wizard.setObjectName("wizard") + wizard.resize(450, 633) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(wizard.sizePolicy().hasHeightForWidth()) + wizard.setSizePolicy(sizePolicy) + wizard.setMinimumSize(QtCore.QSize(450, 0)) + wizard.setMaximumSize(QtCore.QSize(600, 1000)) + wizard.setSizeIncrement(QtCore.QSize(0, 0)) + wizard.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/images/iblrig_logo"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + wizard.setWindowIcon(icon) + wizard.setWindowOpacity(1.0) + wizard.setAutoFillBackground(False) + wizard.setAnimated(False) + wizard.setDocumentMode(False) + self.widget = QtWidgets.QWidget(wizard) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) + self.widget.setSizePolicy(sizePolicy) + self.widget.setObjectName("widget") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.widget) + self.horizontalLayout_2.setContentsMargins(6, 6, 6, 0) + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.tabWidget = QtWidgets.QTabWidget(self.widget) + self.tabWidget.setObjectName("tabWidget") + self.tabSession = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.tabSession.sizePolicy().hasHeightForWidth()) + self.tabSession.setSizePolicy(sizePolicy) + self.tabSession.setObjectName("tabSession") + self.verticalLayoutSession = QtWidgets.QVBoxLayout(self.tabSession) + self.verticalLayoutSession.setObjectName("verticalLayoutSession") + self.uiGroupParameters = QtWidgets.QWidget(self.tabSession) + self.uiGroupParameters.setObjectName("uiGroupParameters") + self.formLayout = QtWidgets.QFormLayout(self.uiGroupParameters) + self.formLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) + self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout.setContentsMargins(0, 0, 0, 0) + self.formLayout.setObjectName("formLayout") + self.labelUser = QtWidgets.QLabel(self.uiGroupParameters) + self.labelUser.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelUser.setObjectName("labelUser") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.labelUser) + self.widget_2 = QtWidgets.QWidget(self.uiGroupParameters) + self.widget_2.setObjectName("widget_2") + self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget_2) + self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + self.uiLineEditUser = QtWidgets.QLineEdit(self.widget_2) + self.uiLineEditUser.setObjectName("uiLineEditUser") + self.horizontalLayout_4.addWidget(self.uiLineEditUser) + self.uiPushButtonLogIn = QtWidgets.QPushButton(self.widget_2) + self.uiPushButtonLogIn.setMinimumSize(QtCore.QSize(100, 0)) + self.uiPushButtonLogIn.setObjectName("uiPushButtonLogIn") + self.horizontalLayout_4.addWidget(self.uiPushButtonLogIn) + self.horizontalLayout_4.setStretch(0, 2) + self.horizontalLayout_4.setStretch(1, 1) + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.widget_2) + self.labelSubject = QtWidgets.QLabel(self.uiGroupParameters) + self.labelSubject.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelSubject.setObjectName("labelSubject") + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.labelSubject) + self.widget_4 = QtWidgets.QWidget(self.uiGroupParameters) + self.widget_4.setObjectName("widget_4") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.widget_4) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + self.uiComboSubject = QtWidgets.QComboBox(self.widget_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiComboSubject.sizePolicy().hasHeightForWidth()) + self.uiComboSubject.setSizePolicy(sizePolicy) + self.uiComboSubject.setObjectName("uiComboSubject") + self.horizontalLayout.addWidget(self.uiComboSubject) + self.lineEditSubject = QtWidgets.QLineEdit(self.widget_4) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEditSubject.sizePolicy().hasHeightForWidth()) + self.lineEditSubject.setSizePolicy(sizePolicy) + self.lineEditSubject.setMinimumSize(QtCore.QSize(100, 0)) + self.lineEditSubject.setMaximumSize(QtCore.QSize(200, 16777215)) + self.lineEditSubject.setLayoutDirection(QtCore.Qt.LeftToRight) + self.lineEditSubject.setObjectName("lineEditSubject") + self.horizontalLayout.addWidget(self.lineEditSubject) + self.horizontalLayout.setStretch(0, 2) + self.horizontalLayout.setStretch(1, 1) + self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.widget_4) + self.labelProject = QtWidgets.QLabel(self.uiGroupParameters) + self.labelProject.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelProject.setObjectName("labelProject") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.labelProject) + self.uiListProjects = QtWidgets.QListView(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiListProjects.sizePolicy().hasHeightForWidth()) + self.uiListProjects.setSizePolicy(sizePolicy) + self.uiListProjects.setMinimumSize(QtCore.QSize(0, 80)) + self.uiListProjects.setMaximumSize(QtCore.QSize(16777215, 80)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, brush) + self.uiListProjects.setPalette(palette) + self.uiListProjects.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.uiListProjects.setFocusPolicy(QtCore.Qt.TabFocus) + self.uiListProjects.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.uiListProjects.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.uiListProjects.setObjectName("uiListProjects") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.uiListProjects) + self.labelProcedure = QtWidgets.QLabel(self.uiGroupParameters) + self.labelProcedure.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelProcedure.setObjectName("labelProcedure") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.labelProcedure) + self.uiListProcedures = QtWidgets.QListView(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiListProcedures.sizePolicy().hasHeightForWidth()) + self.uiListProcedures.setSizePolicy(sizePolicy) + self.uiListProcedures.setMinimumSize(QtCore.QSize(0, 80)) + self.uiListProcedures.setMaximumSize(QtCore.QSize(16777215, 80)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.HighlightedText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.HighlightedText, brush) + self.uiListProcedures.setPalette(palette) + self.uiListProcedures.viewport().setProperty("cursor", QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.uiListProcedures.setFocusPolicy(QtCore.Qt.TabFocus) + self.uiListProcedures.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.uiListProcedures.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.uiListProcedures.setObjectName("uiListProcedures") + self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.uiListProcedures) + self.listViewRemoteDevices = RemoteDevicesListView(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.listViewRemoteDevices.sizePolicy().hasHeightForWidth()) + self.listViewRemoteDevices.setSizePolicy(sizePolicy) + self.listViewRemoteDevices.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.listViewRemoteDevices.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) + self.listViewRemoteDevices.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) + self.listViewRemoteDevices.setObjectName("listViewRemoteDevices") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.listViewRemoteDevices) + self.uiComboTask = QtWidgets.QComboBox(self.uiGroupParameters) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiComboTask.sizePolicy().hasHeightForWidth()) + self.uiComboTask.setSizePolicy(sizePolicy) + self.uiComboTask.setMinimumSize(QtCore.QSize(0, 0)) + self.uiComboTask.setObjectName("uiComboTask") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uiComboTask) + self.labelTask = QtWidgets.QLabel(self.uiGroupParameters) + self.labelTask.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelTask.setObjectName("labelTask") + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.labelTask) + self.scrollArea = QtWidgets.QScrollArea(self.uiGroupParameters) + self.scrollArea.setMinimumSize(QtCore.QSize(0, 110)) + self.scrollArea.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.scrollArea.setWidgetResizable(True) + self.scrollArea.setObjectName("scrollArea") + self.uiGroupTaskParameters = QtWidgets.QWidget() + self.uiGroupTaskParameters.setGeometry(QtCore.QRect(0, 0, 352, 108)) + self.uiGroupTaskParameters.setObjectName("uiGroupTaskParameters") + self.formLayout_2 = QtWidgets.QFormLayout(self.uiGroupTaskParameters) + self.formLayout_2.setObjectName("formLayout_2") + self.scrollArea.setWidget(self.uiGroupTaskParameters) + self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.scrollArea) + self.labelSettings = QtWidgets.QLabel(self.uiGroupParameters) + self.labelSettings.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.labelSettings.setObjectName("labelSettings") + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.labelSettings) + self.labelRemoteDevices = QtWidgets.QLabel(self.uiGroupParameters) + self.labelRemoteDevices.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTop|QtCore.Qt.AlignTrailing) + self.labelRemoteDevices.setObjectName("labelRemoteDevices") + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.labelRemoteDevices) + self.verticalLayoutSession.addWidget(self.uiGroupParameters) + self.widget_3 = QtWidgets.QWidget(self.tabSession) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.widget_3.sizePolicy().hasHeightForWidth()) + self.widget_3.setSizePolicy(sizePolicy) + self.widget_3.setObjectName("widget_3") + self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.widget_3) + self.horizontalLayout_8.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout_8.setObjectName("horizontalLayout_8") + self.uiGroupTools = QtWidgets.QGroupBox(self.widget_3) + self.uiGroupTools.setObjectName("uiGroupTools") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.uiGroupTools) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.uiPushFlush = QtWidgets.QPushButton(self.uiGroupTools) + self.uiPushFlush.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPushFlush.sizePolicy().hasHeightForWidth()) + self.uiPushFlush.setSizePolicy(sizePolicy) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/images/flush"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushFlush.setIcon(icon1) + self.uiPushFlush.setCheckable(True) + self.uiPushFlush.setObjectName("uiPushFlush") + self.verticalLayout_4.addWidget(self.uiPushFlush) + self.uiPushReward = QtWidgets.QPushButton(self.uiGroupTools) + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(":/images/present"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushReward.setIcon(icon2) + self.uiPushReward.setObjectName("uiPushReward") + self.verticalLayout_4.addWidget(self.uiPushReward) + self.uiPushStatusLED = QtWidgets.QPushButton(self.uiGroupTools) + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(":/images/status_led"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.uiPushStatusLED.setIcon(icon3) + self.uiPushStatusLED.setCheckable(True) + self.uiPushStatusLED.setObjectName("uiPushStatusLED") + self.verticalLayout_4.addWidget(self.uiPushStatusLED) + self.horizontalLayout_8.addWidget(self.uiGroupTools) + self.uiGroupSessionControl = QtWidgets.QGroupBox(self.widget_3) + self.uiGroupSessionControl.setObjectName("uiGroupSessionControl") + self.verticalLayout = QtWidgets.QVBoxLayout(self.uiGroupSessionControl) + self.verticalLayout.setObjectName("verticalLayout") + self.uiPushStart = QtWidgets.QPushButton(self.uiGroupSessionControl) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPushStart.sizePolicy().hasHeightForWidth()) + self.uiPushStart.setSizePolicy(sizePolicy) + self.uiPushStart.setStyleSheet("QPushButton { background-color: red; }") + self.uiPushStart.setObjectName("uiPushStart") + self.verticalLayout.addWidget(self.uiPushStart) + self.uiPushPause = QtWidgets.QPushButton(self.uiGroupSessionControl) + self.uiPushPause.setEnabled(False) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uiPushPause.sizePolicy().hasHeightForWidth()) + self.uiPushPause.setSizePolicy(sizePolicy) + self.uiPushPause.setCheckable(True) + self.uiPushPause.setChecked(False) + self.uiPushPause.setObjectName("uiPushPause") + self.verticalLayout.addWidget(self.uiPushPause) + self.horizontalLayout_8.addWidget(self.uiGroupSessionControl) + self.horizontalLayout_8.setStretch(0, 1) + self.horizontalLayout_8.setStretch(1, 1) + self.verticalLayoutSession.addWidget(self.widget_3) + icon4 = QtGui.QIcon() + icon4.addPixmap(QtGui.QPixmap(":/images/wheel"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.tabSession, icon4, "") + self.horizontalLayout_2.addWidget(self.tabWidget) + wizard.setCentralWidget(self.widget) + self.statusbar = QtWidgets.QStatusBar(wizard) + self.statusbar.setEnabled(True) + self.statusbar.setToolTip("") + self.statusbar.setSizeGripEnabled(False) + self.statusbar.setObjectName("statusbar") + wizard.setStatusBar(self.statusbar) + self.uiMenuBar = QtWidgets.QMenuBar(wizard) + self.uiMenuBar.setGeometry(QtCore.QRect(0, 0, 450, 21)) + self.uiMenuBar.setObjectName("uiMenuBar") + self.uiMenuTools = QtWidgets.QMenu(self.uiMenuBar) + self.uiMenuTools.setObjectName("uiMenuTools") + wizard.setMenuBar(self.uiMenuBar) + self.uiActionTrainingLevelV7 = QtWidgets.QAction(wizard) + self.uiActionTrainingLevelV7.setObjectName("uiActionTrainingLevelV7") + self.uiActionCalibrateFrame2ttl = QtWidgets.QAction(wizard) + self.uiActionCalibrateFrame2ttl.setObjectName("uiActionCalibrateFrame2ttl") + self.uiActionCalibrateValve = QtWidgets.QAction(wizard) + self.uiActionCalibrateValve.setObjectName("uiActionCalibrateValve") + self.uiActionValidateHardware = QtWidgets.QAction(wizard) + self.uiActionValidateHardware.setObjectName("uiActionValidateHardware") + self.uiMenuTools.addAction(self.uiActionValidateHardware) + self.uiMenuTools.addAction(self.uiActionCalibrateFrame2ttl) + self.uiMenuTools.addAction(self.uiActionCalibrateValve) + self.uiMenuTools.addAction(self.uiActionTrainingLevelV7) + self.uiMenuBar.addAction(self.uiMenuTools.menuAction()) + self.labelUser.setBuddy(self.uiLineEditUser) + self.labelSubject.setBuddy(self.uiComboSubject) + self.labelProject.setBuddy(self.uiListProjects) + self.labelProcedure.setBuddy(self.uiListProcedures) + self.labelTask.setBuddy(self.uiComboTask) + self.labelSettings.setBuddy(self.scrollArea) + self.labelRemoteDevices.setBuddy(self.listViewRemoteDevices) + + self.retranslateUi(wizard) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(wizard) + wizard.setTabOrder(self.tabWidget, self.uiLineEditUser) + wizard.setTabOrder(self.uiLineEditUser, self.uiPushButtonLogIn) + wizard.setTabOrder(self.uiPushButtonLogIn, self.uiComboSubject) + wizard.setTabOrder(self.uiComboSubject, self.lineEditSubject) + wizard.setTabOrder(self.lineEditSubject, self.uiListProjects) + wizard.setTabOrder(self.uiListProjects, self.uiListProcedures) + wizard.setTabOrder(self.uiListProcedures, self.uiComboTask) + wizard.setTabOrder(self.uiComboTask, self.scrollArea) + wizard.setTabOrder(self.scrollArea, self.listViewRemoteDevices) + wizard.setTabOrder(self.listViewRemoteDevices, self.uiPushFlush) + wizard.setTabOrder(self.uiPushFlush, self.uiPushReward) + wizard.setTabOrder(self.uiPushReward, self.uiPushStatusLED) + wizard.setTabOrder(self.uiPushStatusLED, self.uiPushStart) + wizard.setTabOrder(self.uiPushStart, self.uiPushPause)
+ + +
+[docs] + def retranslateUi(self, wizard): + _translate = QtCore.QCoreApplication.translate + wizard.setWindowTitle(_translate("wizard", "IBLRIG Wizard")) + self.labelUser.setText(_translate("wizard", "&User")) + self.uiLineEditUser.setStatusTip(_translate("wizard", "Enter your user name")) + self.uiLineEditUser.setPlaceholderText(_translate("wizard", "not logged in")) + self.uiPushButtonLogIn.setStatusTip(_translate("wizard", "Click to log user into Alyx")) + self.uiPushButtonLogIn.setText(_translate("wizard", "Log In")) + self.labelSubject.setText(_translate("wizard", "&Subject")) + self.uiComboSubject.setStatusTip(_translate("wizard", "Choose a subject")) + self.lineEditSubject.setStatusTip(_translate("wizard", "Filter subjects by name")) + self.lineEditSubject.setPlaceholderText(_translate("wizard", "Filter")) + self.labelProject.setText(_translate("wizard", "&Project")) + self.uiListProjects.setStatusTip(_translate("wizard", "Select one or several projects")) + self.labelProcedure.setText(_translate("wizard", "P&rocedures")) + self.uiListProcedures.setStatusTip(_translate("wizard", "Select one or several procedures")) + self.listViewRemoteDevices.setStatusTip(_translate("wizard", "Select remote devices")) + self.uiComboTask.setStatusTip(_translate("wizard", "Select a task for the session")) + self.labelTask.setText(_translate("wizard", "&Task")) + self.labelSettings.setText(_translate("wizard", "Settings")) + self.labelRemoteDevices.setText(_translate("wizard", "Remote\n" +"&Devices")) + self.uiGroupTools.setTitle(_translate("wizard", "Tools")) + self.uiPushFlush.setStatusTip(_translate("wizard", "Click to flush the Bpod\'s valve")) + self.uiPushFlush.setText(_translate("wizard", " &Flush Valve ")) + self.uiPushReward.setStatusTip(_translate("wizard", "Click to grant a free reward")) + self.uiPushReward.setText(_translate("wizard", " Fr&ee Reward")) + self.uiPushStatusLED.setStatusTip(_translate("wizard", "Click to toggle the Bpod\'s status LED")) + self.uiPushStatusLED.setText(_translate("wizard", " Status &LED ")) + self.uiGroupSessionControl.setTitle(_translate("wizard", "Session Control")) + self.uiPushStart.setStatusTip(_translate("wizard", "Click to start the session")) + self.uiPushStart.setText(_translate("wizard", "Start")) + self.uiPushPause.setStatusTip(_translate("wizard", "Click to pause the session after the current trial")) + self.uiPushPause.setText(_translate("wizard", "Pause")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabSession), _translate("wizard", "Session")) + self.uiMenuTools.setTitle(_translate("wizard", "Tools")) + self.uiActionTrainingLevelV7.setText(_translate("wizard", "Get Training Level")) + self.uiActionCalibrateFrame2ttl.setText(_translate("wizard", "Calibrate Frame2TTL")) + self.uiActionCalibrateValve.setText(_translate("wizard", "Calibrate Valve")) + self.uiActionValidateHardware.setText(_translate("wizard", "Validate System"))
+
+ +from iblrig.gui.tools import RemoteDevicesListView +from iblrig.gui import resources_rc + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + wizard = QtWidgets.QMainWindow() + ui = Ui_wizard() + ui.setupUi(wizard) + wizard.show() + sys.exit(app.exec_()) +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/validation.html b/_modules/iblrig/gui/validation.html new file mode 100644 index 000000000..b0b709ec2 --- /dev/null +++ b/_modules/iblrig/gui/validation.html @@ -0,0 +1,360 @@ + + + + + + iblrig.gui.validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.validation

+from PyQt5 import QtCore, QtWidgets
+from PyQt5.QtCore import QThreadPool, pyqtSlot
+from PyQt5.QtGui import QFont, QIcon, QStandardItem, QStandardItemModel
+from PyQt5.QtWidgets import QHeaderView
+
+from iblrig.gui.tools import Worker
+from iblrig.gui.ui_validation import Ui_validation
+from iblrig.hardware_validation import Result, Status, Validator, get_all_validators
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings
+
+SECTION_FONT = QFont('', -1, QFont.Bold, False)
+STATUS_ICON: dict[Status, QIcon] = {
+    Status.PASS: QIcon(':/images/validation_pass'),
+    Status.WARN: QIcon(':/images/validation_warn'),
+    Status.FAIL: QIcon(':/images/validation_fail'),
+    Status.INFO: QIcon(':/images/validation_info'),
+    Status.SKIP: QIcon(':/images/validation_skip'),
+    Status.PEND: QIcon(':/images/validation_pending'),
+}
+
+
+
+[docs] +class StatusItem(QStandardItem): + _status: Status + +
+[docs] + def __init__(self, status: Status): + super().__init__() + self.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignRight) + self.status = status
+ + + @property + def status(self): + return self._status + + @status.setter + def status(self, status: Status): + self._status = status + match status: + case Status.PEND: + self.setText('pending') + case Status.PASS: + self.setText('passed') + case Status.WARN: + self.setText('warning') + case Status.FAIL: + self.setText('failed') + case Status.INFO: + self.setText('') + case Status.SKIP: + self.setText('skipped')
+ + + +
+[docs] +class ValidatorItem(QStandardItem): + validator: Validator + _status: Status + +
+[docs] + def __init__(self, validator: type[Validator], hardware_settings: HardwareSettings, rig_settings: RigSettings): + super().__init__() + self.status = Status.PEND + self.validator = validator(hardware_settings=hardware_settings, iblrig_settings=rig_settings, interactive=True) + self.setText(self.validator.name) + self.setFont(SECTION_FONT)
+ + + @property + def status(self) -> Status: + return self._status + + @status.setter + def status(self, status: Status): + self._status = status + self.setIcon(QIcon(STATUS_ICON[status])) + +
+[docs] + def clear(self): + self.status = Status.PEND + while self.hasChildren(): + self.removeRow(0)
+
+ + + +
+[docs] +class SystemValidationDialog(QtWidgets.QDialog, Ui_validation): + validator_items: list[ValidatorItem] = [] + status_items: list[StatusItem] = [] + item_started = QtCore.pyqtSignal(int) + item_result = QtCore.pyqtSignal(int, Result) + item_finished = QtCore.pyqtSignal(int, Status) + +
+[docs] + def __init__(self, *args, hardware_settings: HardwareSettings, rig_settings: RigSettings, **kwargs) -> None: + """ + Dialog for system validation. + + Parameters + ---------- + *args + Arguments to pass to the QDialog constructor. + hardware_settings : HardwareSettings + Pydantic model with data parsed from hardware_settings.yaml + rig_settings : RigSettings + Pydantic model with data parsed from iblrig_settings.yaml + **kwargs + Keyword arguments to pass to the QDialog constructor. + + """ + super().__init__(*args, **kwargs) + self.setupUi(self) + self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowType.WindowContextHelpButtonHint) + + self.worker = Worker(self.run_subprocess) + self.worker.setAutoDelete(False) + self.worker.signals.finished.connect(lambda: self.pushButtonRerun.setEnabled(True)) + self.worker.signals.finished.connect(lambda: self.pushButtonOK.setEnabled(True)) + + self.treeModel = QStandardItemModel() + self.treeModel.setColumnCount(2) + + for validator in get_all_validators(): + self.validator_items.append(ValidatorItem(validator, hardware_settings, rig_settings)) + self.status_items.append(StatusItem(Status.PEND)) + self.status_items[-1].setFont(SECTION_FONT) + self.treeModel.appendRow([self.validator_items[-1], self.status_items[-1]]) + + self.treeView.setModel(self.treeModel) + self.treeView.header().setSectionResizeMode(0, QHeaderView.Stretch) + self.treeView.header().setSectionResizeMode(1, QHeaderView.Fixed) + self.treeView.header().resizeSection(1, 60) + + self.pushButtonOK.clicked.connect(self.close) + self.pushButtonRerun.clicked.connect(self.run) + self.item_started.connect(self.on_item_started) + self.item_result.connect(self.on_item_result) + self.item_finished.connect(self.on_item_finished) + + self.show() + self.run()
+ + +
+[docs] + def run(self): + """Prepare GUI and start worker thread for running validators.""" + self.pushButtonOK.setEnabled(False) + self.pushButtonRerun.setEnabled(False) + self.treeView.expandAll() + for idx, _ in enumerate(self.validator_items): + self.validator_items[idx].clear() + self.status_items[idx].status = Status.PEND + self.treeView.scrollToTop() + self.update() + QThreadPool.globalInstance().tryStart(self.worker)
+ + +
+[docs] + def run_subprocess(self): + """Run all validators in a subprocess.""" + for idx, validator_item in enumerate(self.validator_items): + self.item_started.emit(idx) + results = [] + for result in validator_item.validator.run(): + results.append(result) + self.item_result.emit(idx, result) + + statuses = [r.status for r in results] + if Status.SKIP in statuses: + status = Status.SKIP + elif Status.FAIL in statuses: + status = Status.FAIL + elif Status.WARN in statuses: + status = Status.WARN + else: + status = Status.PASS + self.item_finished.emit(idx, status)
+ + +
+[docs] + @pyqtSlot(int) + def on_item_started(self, idx: int): + self.status_items[idx].setText('running')
+ + +
+[docs] + @pyqtSlot(int, Result) + def on_item_result(self, idx: int, result: Result): + result_item = QStandardItem(result.message) + result_item.setToolTip(result.message) + result_item.setIcon(STATUS_ICON[result.status]) + self.validator_items[idx].appendRow([result_item, QStandardItem('')]) + if result.solution is not None and len(result.solution) > 0: + solution_item = QStandardItem(f'Suggestion: {result.solution}') + solution_item.setIcon(QIcon(':/images/validation_suggestion')) + self.validator_items[idx].appendRow(solution_item) + self.update()
+ + +
+[docs] + @pyqtSlot(int, Status) + def on_item_finished(self, idx: int, status: Status): + self.validator_items[idx].status = status + self.status_items[idx].status = status + if status == Status.PASS: + self.treeView.collapse(self.validator_items[idx].index()) + self.treeView.scrollToBottom() + self.update()
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/valve.html b/_modules/iblrig/gui/valve.html new file mode 100644 index 000000000..1ebdfe901 --- /dev/null +++ b/_modules/iblrig/gui/valve.html @@ -0,0 +1,611 @@ + + + + + + iblrig.gui.valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.valve

+import logging
+from collections import OrderedDict
+from datetime import date
+
+import numpy as np
+import pyqtgraph as pg
+from PyQt5 import QtCore, QtGui, QtWidgets
+from PyQt5.QtCore import QThreadPool
+from pyqtgraph import PlotWidget
+from serial import SerialException
+from typing_extensions import override
+
+from iblrig.gui.tools import Worker
+from iblrig.gui.ui_valve import Ui_valve
+from iblrig.hardware import Bpod
+from iblrig.path_helper import save_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings
+from iblrig.scale import Scale
+from iblrig.valve import Valve, ValveValues
+from pybpodapi.exceptions.bpod_error import BpodErrorException
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class CalibrationPlot: +
+[docs] + def __init__(self, parent: PlotWidget, name: str, color: str, values: ValveValues | None = None): + self._values = values if values is not None else ValveValues([], []) + self._curve = pg.PlotCurveItem(name=name) + self._curve.setPen(color, width=3) + self._points = pg.ScatterPlotItem() + self._points.setPen(color) + self._points.setBrush(color) + self._parent = parent + parent.addItem(self._curve) + parent.addItem(self._points) + self.update()
+ + + @property + def values(self) -> ValveValues: + return self._values + + @values.setter + def values(self, values: ValveValues): + self._values = values + self.update() + +
+[docs] + def update(self): + self._points.setData(x=self.values.open_times_ms, y=self.values.volumes_ul) + if len(self.values.open_times_ms) < 2: + self._curve.setData(x=[], y=[]) + else: + time_range = list(np.linspace(0, self.values.open_times_ms[-1], 100)) + self._curve.setData(x=time_range, y=self.values.ms2ul(time_range))
+ + +
+[docs] + def clear(self): + self.values.clear_data() + self.update()
+
+ + + +
+[docs] +class ValveCalibrationDialog(QtWidgets.QDialog, Ui_valve): + scale: Scale | None = None + scale_initialized = QtCore.pyqtSignal(bool) + scale_text_changed = QtCore.pyqtSignal(str) + scale_stable_changed = QtCore.pyqtSignal(bool) + drop_cleared = QtCore.pyqtSignal(int) + tared = QtCore.pyqtSignal(bool) + calibration_finished = QtCore.pyqtSignal() + start_next_calibration = QtCore.pyqtSignal() + _grams = float('nan') + _stable = False + _next_calibration_step = 1 + _next_calibration_time = float('nan') + _scale_update_ms = 100 + _clear_drop_counter = 0 + +
+[docs] + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.setupUi(self) + + # state machine for GUI logic + self.machine = QtCore.QStateMachine() + self.states: OrderedDict[str, QtCore.QStateMachine] = OrderedDict({}) + + # timers + self.scale_timer = QtCore.QTimer() + self.clear_timer = QtCore.QTimer() + self.clear_timer.setTimerType(QtCore.Qt.TimerType.PreciseTimer) + + # hardware + self.hw_settings: HardwareSettings = self.parent().model.hardware_settings + self.bpod = Bpod(self.hw_settings.device_bpod.COM_BPOD, skip_initialization=True, disable_behavior_ports=[0, 1, 2, 3]) + self.valve = Valve(self.hw_settings.device_valve) + + # UI related ... + self.font_database = QtGui.QFontDatabase + self.font_database.addApplicationFont(':/fonts/7-Segment') + self.lineEditGrams.setFont(QtGui.QFont('7-Segment', 30)) + self.action_grams = self.lineEditGrams.addAction( + QtGui.QIcon(':/images/grams'), QtWidgets.QLineEdit.ActionPosition.TrailingPosition + ) + self.action_stable = self.lineEditGrams.addAction( + QtGui.QIcon(':/images/stable'), QtWidgets.QLineEdit.ActionPosition.LeadingPosition + ) + self.action_grams.setVisible(False) + self.action_stable.setVisible(False) + self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) + self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint) + self.setModal(QtCore.Qt.WindowModality.ApplicationModal) + + # set up plot widget + self.uiPlot.addLegend() + self.old_calibration = CalibrationPlot( + self.uiPlot, f'previous calibration ({self.valve.calibration_date})', 'gray', self.valve.values + ) + self.new_calibration = CalibrationPlot(self.uiPlot, 'new calibration', 'black') + self.uiPlot.hideButtons() + self.uiPlot.setMenuEnabled(False) + self.uiPlot.setMouseEnabled(x=False, y=False) + self.uiPlot.setBackground(None) + self.uiPlot.setLabel('bottom', 'Opening Time [ms]') + self.uiPlot.setLabel('left', 'Volume [μL]') + self.uiPlot.getViewBox().setLimits(xMin=0, yMin=0) + self.uiPlot.getViewBox().enableAutoRange(True) + + # signals & slots + self.scale_text_changed.connect(self.display_scale_text) + self.scale_stable_changed.connect(self.display_scale_stable) + self.pushButtonPulseValve.clicked.connect(self.pulse_valve) + self.pushButtonToggleValve.clicked.connect(self.toggle_valve) + self.pushButtonTareScale.clicked.connect(self.tare) + self.pushButtonSave.setEnabled(False) + self.pushButtonCancel.clicked.connect(self.close) + self.pushButtonRestart.setVisible(False) + self.scale_initialized.connect(self.define_and_start_state_machine) + + # initialize scale + worker = Worker(self.initialize_scale, port=self.hw_settings.device_scale.COM_SCALE) + worker.signals.result.connect(self._on_initialize_scale_result) + QThreadPool.globalInstance().tryStart(worker) + + self.show()
+ + +
+[docs] + @QtCore.pyqtSlot(bool) + def define_and_start_state_machine(self, use_scale: bool = False) -> None: + for state_name in ['start', 'beaker', 'beaker2', 'flow', 'clear', 'tare', 'calibrate', 'finished', 'save']: + self.states[state_name] = QtCore.QState(self.machine) + self.machine.setInitialState(self.states['start']) + + # state 'start': welcome the user and explain what's going on -------------------------------------------------- + self.states['start'].assignProperty(self.labelGuideHead, 'text', 'Welcome') + self.states['start'].assignProperty( + self.labelGuideText, + 'text', + 'This is a step-by-step guide for calibrating the valve of your rig. You can abort the process at any time by ' + 'pressing Cancel or closing this window.', + ) + self.states['start'].assignProperty(self.commandLinkNext, 'enabled', True) + self.states['start'].addTransition(self.commandLinkNext.clicked, self.states['beaker']) + + # state 'beaker': ask user to position beaker on scale --------------------------------------------------------- + self.states['beaker'].assignProperty(self.labelGuideHead, 'text', 'Preparation') + self.states['beaker'].assignProperty( + self.labelGuideText, + 'text', + 'Fill the water reservoir to the level used during experiments.\n\n' + 'Place a small beaker on the scale and position the lick spout directly above.\n\n' + 'The opening of the spout should be placed at a vertical position identical to the one used during ' + 'experiments.', + ) + self.states['beaker'].entered.connect(self.clear_calibration) + self.states['beaker'].assignProperty(self.pushButtonRestart, 'visible', False) + self.states['beaker'].assignProperty(self.commandLinkNext, 'visible', True) + self.states['beaker'].assignProperty(self.commandLinkNext, 'enabled', True) + self.states['beaker'].assignProperty(self.pushButtonSave, 'enabled', False) + self.states['beaker'].assignProperty(self.pushButtonTareScale, 'enabled', use_scale) + self.states['beaker'].assignProperty(self.pushButtonToggleValve, 'enabled', True) + self.states['beaker'].assignProperty(self.pushButtonPulseValve, 'enabled', True) + self.states['beaker'].addTransition(self.commandLinkNext.clicked, self.states['beaker2']) + + # state 'beaker': ask user to position beaker on scale --------------------------------------------------------- + self.states['beaker2'].assignProperty(self.labelGuideHead, 'text', 'Preparation') + self.states['beaker2'].assignProperty( + self.labelGuideText, + 'text', + 'Make sure that neither lick spout nor tubing touch the beaker or the scale and that water drops can ' + 'freely fall into the beaker.', + ) + self.states['beaker2'].addTransition(self.commandLinkNext.clicked, self.states['flow']) + + # state 'flow': prepare flow of water -------------------------------------------------------------------------- + self.states['flow'].assignProperty(self.labelGuideHead, 'text', 'Preparation') + self.states['flow'].assignProperty( + self.labelGuideText, + 'text', + 'Use the valve controls above to advance the flow of the water until there are no visible pockets of air within the ' + 'tubing and first drops start falling into the beaker.', + ) + self.states['flow'].addTransition(self.commandLinkNext.clicked, self.states['clear']) + + # state 'clear': try to clear one drop of water to set a defined start point for calibration ------------------- + self.states['clear'].entered.connect(self.clear_drop) + self.states['clear'].assignProperty(self.pushButtonTareScale, 'enabled', False) + self.states['clear'].assignProperty(self.pushButtonToggleValve, 'enabled', False) + if use_scale: + self.states['clear'].assignProperty(self.pushButtonPulseValve, 'enabled', False) + self.states['clear'].assignProperty(self.commandLinkNext, 'enabled', False) + self.states['clear'].addTransition(self.drop_cleared, self.states['tare']) + else: + self.states['clear'].assignProperty(self.pushButtonPulseValve, 'enabled', True) + self.states['clear'].assignProperty(self.commandLinkNext, 'enabled', True) + self.states['clear'].addTransition(self.commandLinkNext.clicked, self.states['tare']) + + # state 'tare': tare the scale --------------------------------------------------------------------------------- + self.states['tare'].assignProperty(self.pushButtonPulseValve, 'enabled', False) + if use_scale: + self.states['tare'].entered.connect(self.tare) + self.states['tare'].addTransition(self.tared, self.states['calibrate']) + else: + self.states['tare'].assignProperty(self.labelGuideText, 'text', 'Tare the scale.') + self.states['tare'].addTransition(self.commandLinkNext.clicked, self.states['calibrate']) + + # state 'calibrate': perform the actual measurement ------------------------------------------------------------ + self.states['calibrate'].entered.connect(self.calibrate) + self.states['calibrate'].assignProperty(self.commandLinkNext, 'enabled', False) + self.states['calibrate'].addTransition(self.start_next_calibration, self.states['clear']) + self.states['calibrate'].addTransition(self.calibration_finished, self.states['finished']) + + # state 'finished': ask user to save or discard the calibration ------------------------------------------------ + self.states['finished'].assignProperty(self.labelGuideHead, 'text', 'Calibration is finished') + self.states['finished'].assignProperty( + self.labelGuideText, + 'text', + 'Click Save to store the calibration. Close this window or click Cancel to discard the calibration.', + ) + self.states['finished'].assignProperty(self.commandLinkNext, 'visible', False) + self.states['finished'].assignProperty(self.pushButtonSave, 'enabled', True) + self.states['finished'].assignProperty(self.pushButtonRestart, 'visible', True) + self.states['finished'].addTransition(self.pushButtonRestart.clicked, self.states['beaker']) + self.states['finished'].addTransition(self.pushButtonSave.clicked, self.states['save']) + + # state 'save': save calibration and quit ---------------------------------------------------------------------- + self.states['save'].entered.connect(self.save) + self.states['save'].assignProperty(self, 'enabled', False) + + self.machine.start()
+ + +
+[docs] + def clear_calibration(self): + self.new_calibration.clear() + self._next_calibration_time = self.get_next_calibration_time()
+ + +
+[docs] + def get_next_calibration_time(self) -> float | None: + remaining_calibration_times = [ + t for t in self.valve.new_calibration_open_times if t not in self.new_calibration.values.open_times_ms + ] + if len(remaining_calibration_times) > 0: + return max(remaining_calibration_times) + else: + return None
+ + +
+[docs] + def initialize_scale(self, port: str) -> bool: + if port is None: + self.groupBoxScale.setVisible(False) + return False + try: + self.lineEditGrams.setAlignment(QtCore.Qt.AlignCenter) + self.lineEditGrams.setText('Starting') + self.scale = Scale(port) + return True + except (AssertionError, SerialException): + log.error(f'Error initializing OHAUS scale on {port}.') + return False
+ + + def _on_initialize_scale_result(self, success: bool): + if success: + self.lineEditGrams.setEnabled(True) + self.pushButtonTareScale.setEnabled(True) + self.lineEditGrams.setAlignment(QtCore.Qt.AlignRight) + self.lineEditGrams.setText('') + self.scale_timer.timeout.connect(self.get_scale_reading) + self.action_grams.setVisible(True) + self.get_scale_reading() + self.scale_timer.start(self._scale_update_ms) + else: + self.lineEditGrams.setAlignment(QtCore.Qt.AlignCenter) + self.lineEditGrams.setText('Error') + self.scale_initialized.emit(success) + +
+[docs] + def get_scale_reading(self): + grams, stable = self.scale.get_grams() + if grams != self._grams: + self.scale_text_changed.emit(f'{grams:0.2f}') + if stable != self._stable: + self.scale_stable_changed.emit(stable) + self._grams = grams + self._stable = stable
+ + +
+[docs] + @QtCore.pyqtSlot(str) + def display_scale_text(self, value: str): + self.lineEditGrams.setText(value)
+ + +
+[docs] + @QtCore.pyqtSlot(bool) + def display_scale_stable(self, value: bool): + self.action_stable.setVisible(value)
+ + +
+[docs] + def toggle_valve(self): + state = self.pushButtonToggleValve.isChecked() + self.pushButtonToggleValve.setStyleSheet('QPushButton {background-color: rgb(128, 128, 255);}' if state else '') + try: + self.bpod.open_valve(open=state) + except (OSError, BpodErrorException): + self.pushButtonToggleValve.setChecked(False) + self.pushButtonToggleValve.setStyleSheet('')
+ + +
+[docs] + def pulse_valve(self): + self.bpod.pulse_valve(0.05)
+ + +
+[docs] + def clear_drop(self): + self.labelGuideHead.setText('Calibration') + if self.scale is None: + self.labelGuideText.setText( + "Use the 'Pulse Valve' button above to clear one drop of water in order to obtain a defined starting point for " + 'calibration.' + ) + else: + self.labelGuideText.setText( + 'Trying to automatically clear one drop of water to obtain a defined starting point for calibration.' + ) + open_time_s = 0.05 + initial_grams = self.scale.get_stable_grams() + self._clear_drop_counter = 0 + self.clear_timer.timeout.connect(lambda: self.clear_crop_callback(initial_grams, open_time_s)) + self.clear_timer.start(500 + int(open_time_s * 1000))
+ + +
+[docs] + def clear_crop_callback(self, initial_grams: float, duration_s: float = 0.05): + if self.scale.get_grams()[0] > initial_grams + 0.02: + self.clear_timer.stop() + self.clear_timer.disconnect() + self.drop_cleared.emit(self._clear_drop_counter) + return + self._clear_drop_counter += 1 + self.bpod.pulse_valve(duration_s)
+ + +
+[docs] + def tare(self): + self.scale_timer.stop() + self.scale_text_changed.emit('------') + self._grams = float('nan') + worker = Worker(self.scale.tare) + worker.signals.result.connect(self._on_tare_finished) + QThreadPool.globalInstance().tryStart(worker)
+ + + @QtCore.pyqtSlot(object) + def _on_tare_finished(self, success: bool): + self.scale_timer.start(self._scale_update_ms) + self.tared.emit(success) + +
+[docs] + @QtCore.pyqtSlot() + def calibrate(self): + n_samples = int(np.ceil(50 * max(self.valve.new_calibration_open_times) / self._next_calibration_time)) + self.labelGuideText.setText( + f'Getting {n_samples} samples for a valve opening time of {self._next_calibration_time} ms ...' + ) + worker = Worker(self.bpod.pulse_valve_repeatedly, n_samples, self._next_calibration_time / 1e3, 0.2) + worker.signals.result.connect(self._on_repeated_pulse_finished) + QThreadPool.globalInstance().tryStart(worker)
+ + + @QtCore.pyqtSlot(object) + def _on_repeated_pulse_finished(self, n_pulses: int): + if self.scale is None: + ok = False + scale_reading = 0 + while not ok or scale_reading <= 0: + scale_reading, ok = QtWidgets.QInputDialog().getDouble( + self, + 'Enter Scale Reading', + 'Enter measured weight in grams:', + min=0, + max=float('inf'), + decimals=2, + flags=(QtWidgets.QInputDialog().windowFlags() & ~QtCore.Qt.WindowType.WindowContextHelpButtonHint), + ) + grams_per_pulse = scale_reading / n_pulses + else: + scale_reading = self.scale.get_stable_grams() + grams_per_pulse = scale_reading / n_pulses + self.new_calibration.values.add_samples([self._next_calibration_time], [grams_per_pulse]) + self.new_calibration.update() + self._next_calibration_time = self.get_next_calibration_time() + if self._next_calibration_time is None: + self.calibration_finished.emit() + else: + self.start_next_calibration.emit() + +
+[docs] + def save(self) -> None: + valve_settings = self.hw_settings.device_valve + valve_settings.WATER_CALIBRATION_OPEN_TIMES = [float(x) for x in self.new_calibration.values.open_times_ms] + valve_settings.WATER_CALIBRATION_WEIGHT_PERDROP = [float(x) for x in self.new_calibration.values.volumes_ul] + valve_settings.WATER_CALIBRATION_DATE = date.today() + self.parent().model.hardware_settings.device_valve = valve_settings + save_pydantic_yaml(self.parent().model.hardware_settings) + self.labelGuideHead.setText('Settings saved.') + self.labelGuideText.setText('') + QtCore.QTimer.singleShot(1000, self.close)
+ + +
+[docs] + @override + def closeEvent(self, event): + self.clear_timer.stop() + self.scale_timer.stop() + if self.machine.started: + self.machine.stop() + if self.bpod.is_connected: + self.bpod.stop_trial() + self.deleteLater()
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/gui/wizard.html b/_modules/iblrig/gui/wizard.html new file mode 100644 index 000000000..b6b5190b6 --- /dev/null +++ b/_modules/iblrig/gui/wizard.html @@ -0,0 +1,1501 @@ + + + + + + iblrig.gui.wizard — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.gui.wizard

+import argparse
+import ctypes
+import json
+import logging
+import os
+import re
+import shutil
+import subprocess
+import sys
+import traceback
+from collections import OrderedDict
+from dataclasses import dataclass
+from importlib.util import module_from_spec, spec_from_file_location
+from pathlib import Path
+
+import pyqtgraph as pg
+from pydantic import ValidationError
+from PyQt5 import QtCore, QtGui, QtWidgets
+from PyQt5.QtCore import QThreadPool
+from PyQt5.QtWidgets import QStyle
+from requests import HTTPError
+from serial import SerialException
+from typing_extensions import override
+
+import iblrig.hardware_validation
+import iblrig.path_helper
+import iblrig_tasks
+from ibllib.io.raw_data_loaders import load_settings
+from iblrig.base_tasks import BaseSession, EmptySession
+from iblrig.choiceworld import compute_adaptive_reward_volume, get_subject_training_info, training_phase_from_contrast_set
+from iblrig.constants import BASE_DIR
+from iblrig.gui.frame2ttl import Frame2TTLCalibrationDialog
+from iblrig.gui.splash import Splash
+from iblrig.gui.tab_about import TabAbout
+from iblrig.gui.tab_data import TabData
+from iblrig.gui.tab_docs import TabDocs
+from iblrig.gui.tab_log import TabLog
+from iblrig.gui.tools import DiskSpaceIndicator, RemoteDevicesItemModel, Worker
+from iblrig.gui.ui_login import Ui_login
+from iblrig.gui.ui_update import Ui_update
+from iblrig.gui.ui_wizard import Ui_wizard
+from iblrig.gui.validation import SystemValidationDialog
+from iblrig.gui.valve import ValveCalibrationDialog
+from iblrig.hardware import Bpod
+from iblrig.hardware_validation import Status
+from iblrig.misc import get_task_argument_parser
+from iblrig.path_helper import load_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings
+from iblrig.raw_data_loaders import load_task_jsonable
+from iblrig.tools import alyx_reachable, get_lab_location_dict, internet_available
+from iblrig.valve import Valve
+from iblrig.version_management import check_for_updates, get_changelog
+from iblutil.util import Bunch, setup_logger
+from one.webclient import AlyxClient
+from pybpodapi.exceptions.bpod_error import BpodErrorException
+
+try:
+    import iblrig_custom_tasks
+
+    CUSTOM_TASKS = True
+except ImportError:
+    CUSTOM_TASKS = False
+    pass
+
+log = logging.getLogger(__name__)
+pg.setConfigOption('foreground', 'k')
+pg.setConfigOptions(antialias=True)
+
+PROCEDURES = [
+    'Behavior training/tasks',
+    'Ephys recording with acute probe(s)',
+    'Ephys recording with chronic probe(s)',
+    'Fiber photometry',
+    'handling_habituation',
+    'Imaging',
+]
+PROJECTS = ['ibl_neuropixel_brainwide_01', 'practice']
+
+ANSI_COLORS: dict[str, str] = {'31': 'Red', '32': 'Green', '33': 'Yellow', '35': 'Magenta', '36': 'Cyan', '37': 'White'}
+REGEX_STDOUT = re.compile(
+    r'^\x1b\[(?:\d;)?(?:\d+;)?'
+    r'(?P<color>\d+)m[\d-]*\s+'
+    r'(?P<time>[\d\:]+)\s+'
+    r'(?P<level>\w+\s+)'
+    r'(?P<file>[\w\:\.]+)\s+'
+    r'(?P<message>[^\x1b]*)',
+    re.MULTILINE,
+)
+
+
+def _set_list_view_from_string_list(ui_list: QtWidgets.QListView, string_list: list):
+    """Small boiler plate util to set the selection of a list view from a list of strings."""
+    if string_list is None or len(string_list) == 0:
+        return
+    for i, s in enumerate(ui_list.model().stringList()):
+        if s in string_list:
+            ui_list.selectionModel().select(ui_list.model().createIndex(i, 0), QtCore.QItemSelectionModel.Select)
+
+
+
+[docs] +@dataclass +class RigWizardModel: + alyx: AlyxClient | None = None + procedures: list | None = None + projects: list | None = None + task_name: str | None = None + user: str | None = None + subject: str | None = None + session_folder: Path | None = None + test_subject_name = 'test_subject' + free_reward_time: float | None = None + file_iblrig_settings: Path | str | None = None + file_hardware_settings: Path | str | None = None + + def __post_init__(self): + self.iblrig_settings: RigSettings = load_pydantic_yaml(RigSettings, filename=self.file_iblrig_settings, do_raise=True) + self.hardware_settings: HardwareSettings = load_pydantic_yaml( + HardwareSettings, filename=self.file_hardware_settings, do_raise=True + ) + + self.free_reward_time = Valve(self.hardware_settings.device_valve).free_reward_time_sec + + if self.iblrig_settings.ALYX_URL is not None: + self.alyx = AlyxClient(base_url=str(self.iblrig_settings.ALYX_URL), silent=True) + + self.all_users = [self.iblrig_settings['ALYX_USER']] if self.iblrig_settings['ALYX_USER'] else [] + self.all_procedures = sorted(PROCEDURES) + self.all_projects = sorted(PROJECTS) + + # for the tasks, we build a dictionary that contains the task name as key and the path to task.py as value + tasks = sorted([p for p in Path(iblrig_tasks.__file__).parent.rglob('task.py')]) + if CUSTOM_TASKS: + tasks.extend(sorted([p for p in Path(iblrig_custom_tasks.__file__).parent.rglob('task.py')])) + self.all_tasks = OrderedDict({p.parts[-2]: p for p in tasks}) + + # get the subjects from iterating over folders in the the iblrig data path + if self.iblrig_settings['iblrig_local_data_path'] is None: + self.all_subjects = [self.test_subject_name] + else: + folder_subjects = Path(self.iblrig_settings['iblrig_local_data_path']).joinpath( + self.iblrig_settings['ALYX_LAB'], 'Subjects' + ) + self.all_subjects = [self.test_subject_name] + sorted( + [f.name for f in folder_subjects.glob('*') if f.is_dir() and f.name != self.test_subject_name] + ) + +
+[docs] + def get_session(self, task_name: str) -> BaseSession: + """ + Get a session object for the given task name. + + Parameters + ---------- + task_name: str + The name of the task + + Returns + ------- + BaseSession + The session object for the given task name + """ + spec = spec_from_file_location('task', self.all_tasks[task_name]) + task = module_from_spec(spec) + sys.modules[spec.name] = task + spec.loader.exec_module(task) + return task.Session
+ + +
+[docs] + def get_task_extra_parser(self, task_name: str): + """ + Get an extra parser for the given task name. + + Parameters + ---------- + task_name + The name of the task + + Returns + ------- + ArgumentParser + The extra parser for the given task name + """ + return self.get_session(task_name).extra_parser()
+ + +
+[docs] + def get_task_parameters(self, task_name: str) -> Bunch: + """ + Return parameters for the given task. + + Parameters + ---------- + task_name + The name of the task + + Returns + ------- + Bunch + The parameters for the given task + """ + return self.get_session(task_name).read_task_parameter_files()
+ + + @property + def task_file(self) -> Path: + return self.all_tasks.get(self.task_name, None) + +
+[docs] + def login( + self, + username: str, + password: str | None = None, + do_cache: bool = False, + alyx_client: AlyxClient | None = None, + gui: bool = False, + ) -> bool: + # Use predefined AlyxClient for testing purposes: + if alyx_client is not None: + self.alyx = alyx_client + + # Alternatively, try to log in: + else: + try: + self.alyx.authenticate(username, password, do_cache, force=password is not None) + if self.alyx.is_logged_in and self.alyx.user == username: + self.user = self.alyx.user + log.info(f'Logged into {self.alyx.base_url} as {self.alyx.user}') + else: + return False + except HTTPError as e: + if e.errno == 400 and any(x in e.response.text for x in ('credentials', 'required')): + log.error(e.filename) + return False + else: + raise e + + # validate connection and some parameters now that we're connected + try: + self.alyx.rest( + 'locations', + 'partial_update', + id=self.hardware_settings.RIG_NAME, + data={'json': get_lab_location_dict(self.hardware_settings, self.iblrig_settings)}, + ) + except HTTPError as ex: + if ex.response.status_code not in (404, 400): # file not found; auth error + # Likely Alyx is down or server-side issue + message = 'Failed to determine lab location on Alyx' + solution = 'Check if Alyx is reachable' + else: + message = f'Could not find rig name {self.hardware_settings.RIG_NAME} in Alyx' + solution = ( + f'Please check the RIG_NAME key in hardware_settings.yaml and make sure it is created in Alyx here: ' + f'{self.iblrig_settings.ALYX_URL}/admin/misc/lablocation/' + ) + QtWidgets.QMessageBox().critical(None, 'Error', f'{message}\n\n{solution}') + + # get subjects from Alyx: this is the set of subjects that are alive and not stock in the lab defined in settings + rest_subjects = self.alyx.rest( + 'subjects', 'list', alive=True, stock=False, lab=self.iblrig_settings['ALYX_LAB'], no_cache=True + ) + self.all_subjects.remove(self.test_subject_name) + self.all_subjects = [self.test_subject_name] + sorted(set(self.all_subjects + [s['nickname'] for s in rest_subjects])) + + # then get the projects that map to the current user + rest_projects = self.alyx.rest('projects', 'list', no_cache=True) + projects = [p['name'] for p in rest_projects if (username in p['users'] or len(p['users']) == 0)] + self.all_projects = sorted(set(projects + self.all_projects)) + + return True
+ + +
+[docs] + def logout(self): + if not self.alyx.is_logged_in or self.alyx.user is not self.user: + return + log.info(f'User {self.user} logged out') + self.alyx.logout() + self.user = None + self.__post_init__()
+ + +
+[docs] + def free_reward(self): + try: + bpod = Bpod( + self.hardware_settings['device_bpod']['COM_BPOD'], skip_initialization=True, disable_behavior_ports=[1, 2, 3] + ) + bpod.pulse_valve(open_time_s=self.free_reward_time) + except (OSError, BpodErrorException): + log.error('Cannot find bpod - is it connected?') + return
+
+ + + +
+[docs] +class RigWizard(QtWidgets.QMainWindow, Ui_wizard): + training_info: dict = {} + session_info: dict = {} + task_parameters: dict | None = None + new_subject_details = QtCore.pyqtSignal() + append_session: bool = False + previous_subject: str | None = None + +
+[docs] + def __init__(self, debug: bool = False, remote_devices: bool = False): + super().__init__() + self.setupUi(self) + + # load tabs + self.tabLog = TabLog(parent=self.tabWidget) + self.tabData = TabData(parent=self.tabWidget) + self.tabDocs = TabDocs(parent=self.tabWidget) + self.tabAbout = TabAbout(parent=self.tabWidget) + self.tabWidget.addTab(self.tabLog, QtGui.QIcon(':/images/log'), 'Log') + self.tabWidget.addTab(self.tabData, QtGui.QIcon(':/images/sessions'), 'Data') + self.tabWidget.addTab(self.tabDocs, QtGui.QIcon(':/images/help'), 'Docs') + self.tabWidget.addTab(self.tabAbout, QtGui.QIcon(':/images/about'), 'About') + self.tabWidget.setCurrentIndex(0) + + self.debug = debug + self.settings = QtCore.QSettings() + + try: + self.model = RigWizardModel() + except ValidationError as e: + yml = ( + 'hardware_settings.yaml' + if 'hardware' in e.title + else 'iblrig_settings.yaml' + if 'iblrig' in e.title + else 'Settings File' + ) + description = '' + for error in e.errors(): + key = '.'.join(error.get('loc', '')) + val = error.get('input', '') + msg = error.get('msg', '') + description += ( + f'<table>' + f'<tr><td><b>key:</b></td><td><td>{key}</td></tr>\n' + f'<tr><td><b>value:</b></td><td><td>{val}</td></tr>\n' + f'<tr><td><b>error:</b></td><td><td>{msg}</td></tr></table><br>\n' + ) + self._show_error_dialog(title=f'Error validating {yml}', description=description.strip()) + raise e + + # remote devices (only show if at least one device was found) + if remote_devices: + self.remoteDevicesModel = RemoteDevicesItemModel(iblrig_settings=self.model.iblrig_settings) + self.listViewRemoteDevices.setModel(self.remoteDevicesModel) + else: + self.listViewRemoteDevices.setVisible(False) + self.labelRemoteDevices.setVisible(False) + + # task parameters and subject details + self.uiComboTask.currentTextChanged.connect(self._controls_for_task_arguments) + self.uiComboTask.currentTextChanged.connect(self._get_task_parameters) + self.uiComboSubject.currentTextChanged.connect(self._get_subject_details) + self.new_subject_details.connect(self._set_automatic_values) + self.model2view() + + # connect widgets signals to slots + self.uiActionValidateHardware.triggered.connect(self._on_validate_hardware) + self.uiActionCalibrateFrame2ttl.triggered.connect(self._on_calibrate_frame2ttl) + self.uiActionCalibrateValve.triggered.connect(self._on_calibrate_valve) + self.uiActionTrainingLevelV7.triggered.connect(self._on_menu_training_level_v7) + + self.uiPushStart.clicked.connect(self.start_stop) + self.uiPushPause.clicked.connect(self.pause) + self.uiListProjects.clicked.connect(self._enable_ui_elements) + self.uiListProcedures.clicked.connect(self._enable_ui_elements) + self.lineEditSubject.textChanged.connect(self._filter_subjects) + + self.running_task_process = None + self.task_arguments = dict() + self.task_settings_widgets = None + + self.uiPushStart.installEventFilter(self) + self.uiPushStart.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) + self.uiPushPause.setIcon(self.style().standardIcon(QStyle.SP_MediaPause)) + + self.controller2model() + + self.tabWidget.currentChanged.connect(self._on_switch_tab) + + # username + if self.iblrig_settings.ALYX_URL is not None: + self.uiLineEditUser.returnPressed.connect(lambda w=self.uiLineEditUser: self._log_in_or_out(username=w.text())) + self.uiPushButtonLogIn.released.connect(lambda w=self.uiLineEditUser: self._log_in_or_out(username=w.text())) + else: + self.uiLineEditUser.setPlaceholderText('') + self.uiPushButtonLogIn.setEnabled(False) + + # tools + self.uiPushFlush.clicked.connect(self.flush) + self.uiPushReward.clicked.connect(self.model.free_reward) + self.uiPushReward.setStatusTip( + f'Click to grant a free reward ({self.hardware_settings.device_valve.FREE_REWARD_VOLUME_UL:.1f} μL)' + ) + self.uiPushStatusLED.setChecked(self.settings.value('bpod_status_led', True, bool)) + self.uiPushStatusLED.toggled.connect(self.toggle_status_led) + self.toggle_status_led(self.uiPushStatusLED.isChecked()) + + # statusbar / disk stats + local_data = self.iblrig_settings['iblrig_local_data_path'] + local_data = Path(local_data) if local_data else Path.home().joinpath('iblrig_data') + self.uiDiskSpaceIndicator = DiskSpaceIndicator(parent=self.statusbar, directory=local_data) + self.uiDiskSpaceIndicator.setMaximumWidth(70) + self.statusbar.addPermanentWidget(self.uiDiskSpaceIndicator) + self.statusbar.setContentsMargins(0, 0, 6, 0) + + # disable control of LED if Bpod does not have the respective capability + try: + bpod = Bpod(self.hardware_settings['device_bpod']['COM_BPOD'], skip_initialization=True) + self.uiPushStatusLED.setEnabled(bpod.can_control_led) + except SerialException: + pass + + # show splash-screen / store validation results + splash_screen = Splash(parent=self) + splash_screen.exec() + self.validation_results = splash_screen.validation_results + + # check for update + update_worker = Worker(check_for_updates) + update_worker.signals.result.connect(self._on_check_update_result) + QThreadPool.globalInstance().start(update_worker) + + # show GUI + self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowFullscreenButtonHint) + self.move(self.settings.value('pos', self.pos(), QtCore.QPoint)) + self.resize(self.settings.value('size', self.size(), QtCore.QSize)) + self.show() + + # show validation errors / warnings: + if any(results := [r for r in self.validation_results if r.status in (Status.FAIL, Status.WARN)]): + msg_box = QtWidgets.QMessageBox(parent=self) + msg_box.setWindowTitle('IBLRIG System Validation') + msg_box.setIcon(QtWidgets.QMessageBox().Warning) + msg_box.setTextFormat(QtCore.Qt.TextFormat.RichText) + text = f"The following issue{'s were' if len(results) > 1 else ' was'} detected:" + for result in results: + text = ( + text + f"<br><br>\n" + f"<b>{'Warning' if result.status == Status.WARN else 'Failure'}:</b> {result.message}<br>\n" + f"{('<b>Suggestion:</b> ' + result.solution) if result.solution is not None else ''}" + ) + text = text + '<br><br>\nPlease refer to the System Validation tool for more details.' + msg_box.setText(text) + msg_box.exec()
+ + + @property + def iblrig_settings(self) -> RigSettings: + return self.model.iblrig_settings + + @property + def hardware_settings(self) -> HardwareSettings: + return self.model.hardware_settings + + def _get_task_parameters(self, task_name): + worker = Worker(self.model.get_task_parameters, task_name) + worker.signals.result.connect(self._on_task_parameters_result) + QThreadPool.globalInstance().start(worker) + + def _on_task_parameters_result(self, result): + self.task_parameters = result + self._get_subject_details(self.uiComboSubject.currentText()) + + def _get_subject_details(self, subject_name: str): + if not isinstance(subject_name, str) or self.task_parameters is None: + return + worker = Worker( + get_subject_training_info, + subject_name=subject_name, + task_name=self.uiComboTask.currentText(), + stim_gain=self.task_parameters.get('AG_INIT_VALUE'), + stim_gain_on_error=self.task_parameters.get('STIM_GAIN'), + default_reward=self.task_parameters.get('REWARD_AMOUNT_UL'), + ) + worker.signals.result.connect(self._on_subject_details_result) + QThreadPool.globalInstance().start(worker) + + def _on_subject_details_result(self, result): + self.training_info, self.session_info = result + self.new_subject_details.emit() + + def _show_error_dialog( + self, + title: str, + description: str, + issues: list[str] | None = None, + suggestions: list[str] | None = None, + leads: list[str] | None = None, + ): + text = description.strip() + + def build_list(items: list[str] or None, header_singular: str, header_plural: str | None = None): + nonlocal text + if items is None or len(items) == 0: + return + if len(items) > 1: + if header_plural is None: + header_plural = header_singular.strip() + 's' + text += f'<br><br>{header_plural}:<ul>' + else: + text += f'<br><br>{header_singular.strip()}:<ul>' + for item in items: + text += f'<li>{item.strip()}</li>' + text += '</ul>' + + build_list(issues, 'Possible issue') + build_list(suggestions, 'Suggested action') + build_list(leads, 'Possible lead') + QtWidgets.QMessageBox.critical(self, title, text) + + def _on_switch_tab(self, index): + # if self.tabWidget.tabText(index) == 'Session': + # QtCore.QTimer.singleShot(1, lambda: self.resize(self.minimumSizeHint())) + # self.adjustSize() + pass + + def _on_validate_hardware(self) -> None: + SystemValidationDialog(self, hardware_settings=self.hardware_settings, rig_settings=self.iblrig_settings) + + def _on_calibrate_frame2ttl(self) -> None: + Frame2TTLCalibrationDialog(self, hardware_settings=self.hardware_settings) + + def _on_calibrate_valve(self) -> None: + ValveCalibrationDialog(self) + + def _on_menu_training_level_v7(self) -> None: + """ + Prompt user for a session path to get v7 training level. + + This code will be removed and is here only for convenience while users transition from v7 to v8 + """ + # get session path + if not (local_path := Path(r'C:\iblrig_data\Subjects')).exists(): + local_path = self.iblrig_settings.iblrig_local_data_path + session_path = QtWidgets.QFileDialog.getExistingDirectory( + self, 'Select Session Path', str(local_path), QtWidgets.QFileDialog.ShowDirsOnly + ) + if session_path is None or session_path == '': + return + + # get trials table + file_jsonable = next(Path(session_path).glob('raw_behavior_data/_iblrig_taskData.raw.jsonable'), None) + if file_jsonable is None: + QtWidgets.QMessageBox().critical(self, 'Error', f'No jsonable found in {session_path}') + return + trials_table, _ = load_task_jsonable(file_jsonable) + if trials_table.empty: + QtWidgets.QMessageBox().critical(self, 'Error', f'No trials found in {session_path}') + return + + # get task settings + task_settings = load_settings(session_path, task_collection='raw_behavior_data') + if task_settings is None: + QtWidgets.QMessageBox().critical(self, 'Error', f'No task settings found in {session_path}') + return + + # compute values + contrast_set = trials_table['signed_contrast'].abs().unique() + training_phase = training_phase_from_contrast_set(contrast_set) + previous_reward_volume = ( + task_settings.get('ADAPTIVE_REWARD_AMOUNT_UL') + or task_settings.get('REWARD_AMOUNT_UL') + or task_settings.get('REWARD_AMOUNT') + ) + reward_amount = compute_adaptive_reward_volume( + subject_weight_g=task_settings['SUBJECT_WEIGHT'], + reward_volume_ul=previous_reward_volume, + delivered_volume_ul=trials_table['reward_amount'].sum(), + ntrials=trials_table.shape[0], + ) + stim_gain = trials_table['stim_gain'].values[-1] + + # display results + box = QtWidgets.QMessageBox(parent=self) + box.setIcon(QtWidgets.QMessageBox.Information) + box.setModal(False) + box.setWindowTitle('Training Level') + box.setText( + f'{session_path}\n\n' + f'training phase:\t{training_phase}\n' + f'reward:\t{reward_amount:.2f} uL\n' + f'stimulus gain:\t{stim_gain}' + ) + if self.uiComboTask.currentText() == '_iblrig_tasks_trainingChoiceWorld': + box.setStandardButtons(QtWidgets.QMessageBox.Apply | QtWidgets.QMessageBox.Close) + else: + box.setStandardButtons(QtWidgets.QMessageBox.Close) + box.exec() + if box.clickedButton() == box.button(QtWidgets.QMessageBox.Apply): + self.uiGroupTaskParameters.findChild(QtWidgets.QWidget, '--adaptive_gain').setValue(stim_gain) + self.uiGroupTaskParameters.findChild(QtWidgets.QWidget, '--adaptive_reward').setValue(reward_amount) + self.uiGroupTaskParameters.findChild(QtWidgets.QWidget, '--training_phase').setValue(training_phase) + + def _on_check_update_result(self, result: tuple[bool, str]) -> None: + """ + Handle the result of checking for updates. + + Parameters + ---------- + result : tuple[bool, str | None] + A tuple containing a boolean flag indicating update availability (result[0]) + and the remote version string (result[1]). + + Returns + ------- + None + """ + if result[0]: + UpdateNotice(parent=self, version=result[1]) + + def _log_in_or_out(self, username: str) -> bool: + # Routine for logging out: + if self.uiPushButtonLogIn.text() == 'Log Out': + self.model.logout() + self.uiLineEditUser.setText('') + self.uiLineEditUser.setReadOnly(False) + for action in self.uiLineEditUser.actions(): + self.uiLineEditUser.removeAction(action) + self.uiLineEditUser.setStyleSheet('') + self.uiLineEditUser.actions() + self.uiPushButtonLogIn.setText('Log In') + return True + + # Routine for logging in: + # 1) Try to log in with just the username. This will succeed if the credentials for the respective user are cached. We + # also try to catch connection issues and show helpful error messages. + try: + logged_in = self.model.login(username, gui=True) + except ConnectionError: + if not internet_available(timeout=1, force_update=True): + self._show_error_dialog( + title='Error connecting to Alyx', + description='Your computer appears to be offline.', + suggestions=['Check your internet connection.'], + ) + elif not alyx_reachable(): + self._show_error_dialog( + title='Error connecting to Alyx', + description=f'Cannot connect to {self.iblrig_settings.ALYX_URL}', + leads=[ + 'Is `ALYX_URL` in `iblrig_settings.yaml` set correctly?', + 'Is your machine allowed to connect to Alyx?', + 'Is the Alyx server up and running nominally?', + ], + ) + return False + + # 2) If there is no cached session for the given user and we can connect to Alyx: show the password dialog and loop + # until, either, the login was successful or the cancel button was pressed. + if not logged_in: + password = '' + remember = False + while not logged_in: + dlg = LoginWindow(parent=self, username=username, password=password, remember=remember) + if dlg.result(): + username = dlg.lineEditUsername.text() + password = dlg.lineEditPassword.text() + remember = dlg.checkBoxRememberMe.isChecked() + dlg.deleteLater() + logged_in = self.model.login(username=username, password=password, do_cache=remember, gui=True) + else: + dlg.deleteLater() + break + + # 3) Finally, if the login was successful, we need to apply some changes to the GUI + if logged_in: + self.uiLineEditUser.addAction(QtGui.QIcon(':/images/check'), QtWidgets.QLineEdit.ActionPosition.TrailingPosition) + self.uiLineEditUser.setText(username) + self.uiLineEditUser.setReadOnly(True) + self.uiLineEditUser.setStyleSheet('background-color: rgb(246, 245, 244);') + self.uiPushButtonLogIn.setText('Log Out') + self.model2view() + return logged_in + +
+[docs] + @override + def eventFilter(self, obj, event): + if obj == self.uiPushStart and event.type() in [QtCore.QEvent.HoverEnter, QtCore.QEvent.HoverLeave]: + for widget in [self.uiListProcedures, self.uiListProjects]: + if len(widget.selectedIndexes()) > 0: + continue + match event.type(): + case QtCore.QEvent.HoverEnter: + widget.setStyleSheet('QListView { background-color: pink; border: 1px solid red; }') + case _: + widget.setStyleSheet('') + return True + return False
+ + +
+[docs] + @override + def closeEvent(self, event) -> None: + def accept() -> None: + self.settings.setValue('pos', self.pos()) + self.settings.setValue('size', self.size()) + self.settings.setValue('bpod_status_led', self.uiPushStatusLED.isChecked()) + self.toggle_status_led(is_toggled=True) + bpod = Bpod(self.hardware_settings['device_bpod']['COM_BPOD']) # bpod is a singleton + bpod.close() + event.accept() + + if self.running_task_process is None: + accept() + else: + msg_box = QtWidgets.QMessageBox(parent=self) + msg_box.setWindowTitle('Hold on') + msg_box.setText('A task is running - do you really want to quit?') + msg_box.setStandardButtons(QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes) + msg_box.setIcon(QtWidgets.QMessageBox().Question) + match msg_box.exec_(): + case QtWidgets.QMessageBox.No: + event.ignore() + case QtWidgets.QMessageBox.Yes: + self.setEnabled(False) + self.repaint() + self.start_stop() + accept()
+ + +
+[docs] + def model2view(self): + # stores the current values in the model + self.controller2model() + # set the default values + self.uiComboTask.setModel(QtCore.QStringListModel(list(self.model.all_tasks.keys()))) + self.uiComboSubject.setModel(QtCore.QStringListModel(self.model.all_subjects)) + self.uiListProcedures.setModel(QtCore.QStringListModel(self.model.all_procedures)) + self.uiListProjects.setModel(QtCore.QStringListModel(self.model.all_projects)) + # set the selections + self.uiComboTask.setCurrentText(self.model.task_name) + self.uiComboSubject.setCurrentText(self.model.subject) + _set_list_view_from_string_list(self.uiListProcedures, self.model.procedures) + _set_list_view_from_string_list(self.uiListProjects, self.model.projects) + self._enable_ui_elements()
+ + +
+[docs] + def controller2model(self): + self.model.procedures = [i.data() for i in self.uiListProcedures.selectedIndexes()] + self.model.projects = [i.data() for i in self.uiListProjects.selectedIndexes()] + self.model.task_name = self.uiComboTask.currentText() + self.model.subject = self.uiComboSubject.currentText()
+ + + def _controls_for_task_arguments(self, task_name: str): + self.controller2model() + self.task_arguments = dict() + + # collect & filter list of parser arguments (general & task specific) + args = sorted(get_task_argument_parser()._actions, key=lambda x: x.dest) + args = sorted(self.model.get_task_extra_parser(self.model.task_name)._actions, key=lambda x: x.dest) + args + args = [ + x + for x in args + if not any( + set(x.option_strings).intersection( + [ + '--subject', + '--user', + '--projects', + '--log-level', + '--procedures', + '--weight', + '--help', + '--append', + '--no-interactive', + '--stub', + '--wizard', + '--remote', + ] + ) + ) + ] + + group = self.uiGroupTaskParameters + layout = group.layout() + self.task_settings_widgets = [None] * len(args) + + while layout.rowCount(): + layout.removeRow(0) + + for arg in args: + param = str(max(arg.option_strings, key=len)) + label = param.replace('_', ' ').replace('--', '').title() + + # create widget for bool arguments + if isinstance(arg, argparse._StoreTrueAction | argparse._StoreFalseAction): + widget = QtWidgets.QCheckBox() + widget.setTristate(False) + if arg.default: + widget.setCheckState(arg.default * 2) + widget.toggled.connect(lambda val, p=param: self._set_task_arg(p, val > 0)) + widget.toggled.emit(widget.isChecked() > 0) + + # create widget for string arguments + elif arg.type in (str, None): + # string options (-> combo-box) + if isinstance(arg.choices, list): + widget = QtWidgets.QComboBox() + widget.addItems(arg.choices) + if arg.default: + widget.setCurrentIndex([widget.itemText(x) for x in range(widget.count())].index(arg.default)) + widget.currentTextChanged.connect(lambda val, p=param: self._set_task_arg(p, val)) + widget.currentTextChanged.emit(widget.currentText()) + + # list of strings (-> line-edit) + elif arg.nargs == '+': + widget = QtWidgets.QLineEdit() + if arg.default: + widget.setText(', '.join(arg.default)) + widget.editingFinished.connect( + lambda p=param, w=widget: self._set_task_arg(p, [x.strip() for x in w.text().split(',')]) + ) + widget.editingFinished.emit() + + # single string (-> line-edit) + else: + widget = QtWidgets.QLineEdit() + if arg.default: + widget.setText(arg.default) + widget.editingFinished.connect(lambda p=param, w=widget: self._set_task_arg(p, w.text())) + widget.editingFinished.emit() + + # create widget for list of floats + elif arg.type is float and arg.nargs == '+': + widget = QtWidgets.QLineEdit() + if arg.default: + widget.setText(str(arg.default)[1:-1]) + widget.editingFinished.connect( + lambda p=param, w=widget: self._set_task_arg(p, [x.strip() for x in w.text().split(',')]) + ) + widget.editingFinished.emit() + + # create widget for adaptive gain + elif arg.dest == 'adaptive_gain': + widget = QtWidgets.QDoubleSpinBox() + widget.setDecimals(1) + + # create widget for numerical arguments + elif arg.type in [float, int]: + if arg.type is float: + widget = QtWidgets.QDoubleSpinBox() + widget.setDecimals(1) + else: + widget = QtWidgets.QSpinBox() + if arg.default: + widget.setValue(arg.default) + widget.valueChanged.connect(lambda val, p=param: self._set_task_arg(p, str(val))) + widget.valueChanged.emit(widget.value()) + + # no other argument types supported for now + else: + continue + + # add custom widget properties + widget.setObjectName(param) + widget.setProperty('parameter_name', param) + widget.setProperty('parameter_dest', arg.dest) + + # display help strings as status tip + if arg.help: + widget.setStatusTip(arg.help) + + # some customizations + match widget.property('parameter_dest'): + case 'probability_left' | 'probability_opto_stim': + widget.setMinimum(0.0) + widget.setMaximum(1.0) + widget.setSingleStep(0.1) + widget.setDecimals(2) + + case 'contrast_set_probability_type': + label = 'Probability Type' + + case 'session_template_id': + label = 'Session Template ID' + widget.setMinimum(0) + widget.setMaximum(11) + + case 'delay_secs': + label = 'Initial Delay, s' + widget.setMaximum(86400) + + case 'training_phase': + widget.setSpecialValueText('automatic') + widget.setMaximum(5) + widget.setMinimum(-1) + widget.setValue(-1) + + case 'adaptive_reward': + label = 'Reward Amount, μl' + minimum = 1.4 + widget.setSpecialValueText('automatic') + widget.setMaximum(3) + widget.setSingleStep(0.1) + widget.setMinimum(minimum) + widget.setValue(widget.minimum()) + widget.valueChanged.connect( + lambda val, a=arg, m=minimum: self._set_task_arg(a.option_strings[0], str(val if val > m else -1)) + ) + widget.valueChanged.emit(widget.value()) + + case 'reward_set_ul': + label = 'Reward Set, μl' + + case 'adaptive_gain': + label = 'Stimulus Gain' + minimum = 0 + widget.setSpecialValueText('automatic') + widget.setSingleStep(0.1) + widget.setMinimum(minimum) + widget.setValue(widget.minimum()) + widget.valueChanged.connect( + lambda val, a=arg, m=minimum: self._set_task_arg(a.option_strings[0], str(val) if val > m else 'None') + ) + widget.valueChanged.emit(widget.value()) + + case 'reward_amount_ul': + label = 'Reward Amount, μl' + widget.setSingleStep(0.1) + widget.setMinimum(0) + + case 'stim_gain': + label = 'Stimulus Gain' + + case 'stim_reverse': + label = 'Reverse Stimulus' + + case 'duration_spontaneous': + label = 'Spontaneous Activity, s' + widget.setMinimum(0) + widget.setMaximum(60 * 60 * 24 - 1) + widget.setValue(arg.default) + + widget.wheelEvent = lambda event: None + layout.addRow(self.tr(label), widget) + + # add label to indicate absence of task specific parameters + if layout.rowCount() == 0: + layout.addRow(self.tr('(none)'), None) + layout.itemAt(0, 0).widget().setEnabled(False) + + def _set_automatic_values(self): + def _helper(name: str, destination: str, str_format: str): + value = self.training_info.get(name) + if (widget := self.uiGroupTaskParameters.findChild(QtWidgets.QWidget, destination)) is not None: + if value is None: + default = ' (default)' if self.session_info is None else '' + widget.setSpecialValueText(f'automatic{default}') + else: + default = ' (default)' if self.session_info is None else '' + widget.setSpecialValueText(f'automatic: {value:{str_format}}{default}') + + _helper('training_phase', '--training_phase', 'd') + _helper('adaptive_reward', '--adaptive_reward', '0.1f') + _helper('adaptive_gain', '--adaptive_gain', '0.1f') + + def _set_task_arg(self, key, value): + self.task_arguments[key] = value + + def _filter_subjects(self): + filter_str = self.lineEditSubject.text().lower() + result = [s for s in self.model.all_subjects if filter_str in s.lower()] + if len(result) == 0: + result = [self.model.test_subject_name] + self.uiComboSubject.setModel(QtCore.QStringListModel(result)) + +
+[docs] + def pause(self): + self.uiPushPause.setStyleSheet('QPushButton {background-color: yellow;}' if self.uiPushPause.isChecked() else '') + match self.uiPushPause.isChecked(): + case True: + print('Pausing after current trial ...') + if self.model.session_folder.exists(): + self.model.session_folder.joinpath('.pause').touch() + case False: + print('Resuming ...') + if self.model.session_folder.joinpath('.pause').exists(): + self.model.session_folder.joinpath('.pause').unlink()
+ + +
+[docs] + def start_stop(self): + match self.uiPushStart.text(): + case 'Start': + self.uiPushStart.setText('Stop') + self.uiPushStart.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) + self._enable_ui_elements() + + # Manage appended session + self.append_session = False + if self.previous_subject == self.model.subject and not self.model.hardware_settings.MAIN_SYNC: + self.append_session = ( + QtWidgets.QMessageBox.question( + self, + 'Appended Session', + 'Would you like to append to the previous session?', + QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, + QtWidgets.QMessageBox.No, + ) + == QtWidgets.QMessageBox.Yes + ) + + # Manage subject weight + dlg = QtWidgets.QInputDialog() + weight, ok = dlg.getDouble( + self, + 'Subject Weight', + 'Subject Weight (g):', + value=0, + min=0, + decimals=2, + flags=dlg.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint, + ) + if not ok or weight == 0: + self.uiPushStart.setText('Start') + self.uiPushStart.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) + self._enable_ui_elements() + return + + self.controller2model() + + logging.disable(logging.INFO) + task = EmptySession(subject=self.model.subject, append=self.append_session, interactive=False) + logging.disable(logging.NOTSET) + self.model.session_folder = task.paths['SESSION_FOLDER'] + if self.model.session_folder.joinpath('.stop').exists(): + self.model.session_folder.joinpath('.stop').unlink() + self.model.raw_data_folder = task.paths['SESSION_RAW_DATA_FOLDER'] + + # disable Bpod status LED + bpod = Bpod(self.hardware_settings['device_bpod']['COM_BPOD']) + bpod.set_status_led(False) + + # close Bpod singleton so subprocess can access use the port + bpod.close() + + # build the argument list for the subprocess + cmd = [] + if self.model.task_name: + cmd.extend([str(self.model.task_file)]) + if self.model.user: + cmd.extend(['--user', self.model.user]) + if self.model.subject: + cmd.extend(['--subject', self.model.subject]) + if self.model.procedures: + cmd.extend(['--procedures', *self.model.procedures]) + if self.model.projects: + cmd.extend(['--projects', *self.model.projects]) + if len(remotes := self.listViewRemoteDevices.getDevices()) > 0: + cmd.extend(['--remote', *remotes]) + for key, value in self.task_arguments.items(): + if isinstance(value, list): + cmd.extend([key] + value) + elif isinstance(value, bool): + if value is True: + cmd.append(key) + else: + pass + else: + cmd.extend([key, value]) + cmd.extend(['--weight', f'{weight}']) + cmd.extend(['--log-level', 'DEBUG' if self.debug else 'INFO']) + cmd.append('--wizard') + if self.append_session: + cmd.append('--append') + if self.running_task_process is None: + self.tabLog.clear() + self.tabLog.appendText(f'Starting subprocess: {self.model.task_name} ...\n', 'White') + log.info('Starting subprocess') + log.info(subprocess.list2cmdline(cmd)) + self.running_task_process = QtCore.QProcess() + self.running_task_process.setWorkingDirectory(BASE_DIR) + self.running_task_process.setProcessChannelMode(QtCore.QProcess.SeparateChannels) + self.running_task_process.finished.connect(self._on_task_finished) + self.running_task_process.readyReadStandardOutput.connect(self._on_read_standard_output) + self.running_task_process.readyReadStandardError.connect(self._on_read_standard_error) + self.running_task_process.start(shutil.which('python'), cmd) + self.uiPushStart.setStatusTip('stop the session after the current trial') + self.uiPushStart.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) + self.tabWidget.setCurrentIndex(self.tabWidget.indexOf(self.tabLog)) + case 'Stop': + self.uiPushStart.setEnabled(False) + if self.model.session_folder and self.model.session_folder.exists(): + self.model.session_folder.joinpath('.stop').touch()
+ + + def _on_read_standard_output(self): + """ + Read and process standard output entries. + + Reads standard output from a running task process, processes each entry, + extracts color information, sets character color in the QPlainTextEdit widget, + and appends time and message information to the widget. + """ + data = self.running_task_process.readAllStandardOutput().data().decode('utf-8', 'ignore').strip() + entries = re.finditer(REGEX_STDOUT, data) + for entry in entries: + color = ANSI_COLORS.get(entry.groupdict().get('color', '37'), 'White') + time = entry.groupdict().get('time', '') + msg = entry.groupdict().get('message', '') + self.tabLog.appendText(f'{time} {msg}', color) + if self.debug: + print(data) + + def _on_read_standard_error(self): + """ + Read and process standard error entries. + + Reads standard error from a running task process, sets character color + in the QPlainTextEdit widget to indicate an error (Red), and appends + the error message to the widget. + """ + data = self.running_task_process.readAllStandardError().data().decode('utf-8', 'ignore').strip() + self.tabLog.appendText(data, 'Red') + if self.debug: + print(data) + + def _on_task_finished(self, exit_code, exit_status): + self.tabLog.appendText('\nSubprocess finished.', 'White') + if exit_code: + msg_box = QtWidgets.QMessageBox(parent=self) + msg_box.setWindowTitle('Oh no!') + msg_box.setText('The task was terminated with an error.\nPlease check the log for details.') + msg_box.setIcon(QtWidgets.QMessageBox().Critical) + msg_box.exec_() + + self.running_task_process = None + + # re-enable UI elements + self.uiPushStart.setText('Start') + self.uiPushStart.setStatusTip('start the session') + self.uiPushStart.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) + self._enable_ui_elements() + + # recall state of Bpod status LED + bpod = Bpod(self.hardware_settings['device_bpod']['COM_BPOD']) + bpod.set_status_led(self.uiPushStatusLED.isChecked()) + + if (task_settings_file := Path(self.model.raw_data_folder).joinpath('_iblrig_taskSettings.raw.json')).exists(): + with open(task_settings_file) as fid: + session_data = json.load(fid) + + # check if session was a dud + if ( + (ntrials := session_data['NTRIALS']) < 42 + and not any([x in self.model.task_name for x in ('spontaneous', 'passive')]) + and not self.append_session + ): + answer = QtWidgets.QMessageBox.question( + self, + 'Is this a dud?', + f"The session consisted of only {ntrials:d} trial" + f"{'s' if ntrials > 1 else ''} and appears to be a dud.\n\n" + f"Should it be deleted?", + ) + if answer == QtWidgets.QMessageBox.Yes: + shutil.rmtree(self.model.session_folder) + self.previous_subject = None + return + self.previous_subject = self.model.subject + + # manage poop count + dlg = QtWidgets.QInputDialog() + droppings, ok = dlg.getInt( + self, + 'Droppings', + 'Number of droppings:', + value=0, + min=0, + flags=dlg.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint, + ) + session_data['POOP_COUNT'] = droppings + with open(task_settings_file, 'w') as fid: + json.dump(session_data, fid, indent=4, sort_keys=True, default=str) + +
+[docs] + def flush(self): + # paint button blue when in toggled state + self.uiPushFlush.setStyleSheet( + 'QPushButton {background-color: rgb(128, 128, 255);}' if self.uiPushFlush.isChecked() else '' + ) + self._enable_ui_elements() + + try: + bpod = Bpod( + self.hardware_settings['device_bpod']['COM_BPOD'], + skip_initialization=True, + disable_behavior_ports=[1, 2, 3], + ) + bpod.open_valve(self.uiPushFlush.isChecked()) + except (OSError, BpodErrorException): + print(traceback.format_exc()) + print('Cannot find bpod - is it connected?') + self.uiPushFlush.setChecked(False) + self.uiPushFlush.setStyleSheet('') + return
+ + +
+[docs] + def toggle_status_led(self, is_toggled: bool): + # paint button green when in toggled state + self.uiPushStatusLED.setStyleSheet('QPushButton {background-color: rgb(128, 255, 128);}' if is_toggled else '') + self._enable_ui_elements() + + try: + bpod = Bpod(self.hardware_settings['device_bpod']['COM_BPOD'], skip_initialization=True) + bpod.set_status_led(is_toggled) + except (OSError, BpodErrorException, AttributeError): + self.uiPushStatusLED.setChecked(False) + self.uiPushStatusLED.setStyleSheet('')
+ + + def _enable_ui_elements(self): + is_running = self.uiPushStart.text() == 'Stop' + + self.uiPushStart.setEnabled( + not self.uiPushFlush.isChecked() + and len(self.uiListProjects.selectedIndexes()) > 0 + and len(self.uiListProcedures.selectedIndexes()) > 0 + ) + self.uiPushPause.setEnabled(is_running) + self.uiPushFlush.setEnabled(not is_running) + self.uiPushReward.setEnabled(not is_running) + self.uiPushStatusLED.setEnabled(not is_running) + self.uiGroupParameters.setEnabled(not is_running) + self.uiGroupTaskParameters.setEnabled(not is_running) + self.uiGroupTools.setEnabled(not is_running) + self.repaint()
+ + + +
+[docs] +class LoginWindow(QtWidgets.QDialog, Ui_login): +
+[docs] + def __init__(self, parent: RigWizard, username: str = '', password: str = '', remember: bool = False): + super().__init__(parent) + self.setupUi(self) + self.layout().setSizeConstraint(QtWidgets.QLayout.SetFixedSize) + self.labelServer.setText(str(parent.iblrig_settings['ALYX_URL'])) + self.lineEditUsername.setText(username) + self.lineEditPassword.setText(password) + self.checkBoxRememberMe.setChecked(remember) + self.lineEditUsername.textChanged.connect(self._on_text_changed) + self.lineEditPassword.textChanged.connect(self._on_text_changed) + self.toggle_password = self.lineEditPassword.addAction( + QtGui.QIcon(':/images/hide'), QtWidgets.QLineEdit.ActionPosition.TrailingPosition + ) + self.toggle_password.triggered.connect(self._toggle_password_visibility) + self.toggle_password.setCheckable(True) + if len(username) > 0: + self.lineEditPassword.setFocus() + self._on_text_changed() + self.exec()
+ + + def _on_text_changed(self): + enable_ok = len(self.lineEditUsername.text()) > 0 and len(self.lineEditPassword.text()) > 0 + self.buttonBox.button(self.buttonBox.Ok).setEnabled(enable_ok) + + def _toggle_password_visibility(self): + if self.toggle_password.isChecked(): + self.toggle_password.setIcon(QtGui.QIcon(':/images/show')) + self.lineEditPassword.setEchoMode(QtWidgets.QLineEdit.EchoMode.Normal) + else: + self.toggle_password.setIcon(QtGui.QIcon(':/images/hide')) + self.lineEditPassword.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password)
+ + + +
+[docs] +class UpdateNotice(QtWidgets.QDialog, Ui_update): + """ + A dialog for displaying update notices. + + This class is used to create a dialog for displaying update notices. + It shows information about the available update and provides a changelog. + + Parameters + ---------- + parent : QtWidgets.QWidget + The parent widget associated with this dialog. + + update_available : bool + Indicates if an update is available. + + version : str + The version of the available update. + """ + +
+[docs] + def __init__(self, parent: QtWidgets.QWidget, version: str) -> None: + super().__init__(parent) + self.setupUi(self) + self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) + self.uiLabelHeader.setText(f'Update to iblrig {version} is available.') + self.uiTextBrowserChanges.setMarkdown(get_changelog()) + self.setWindowFlags(self.windowFlags() & ~QtCore.Qt.WindowContextHelpButtonHint) + self.exec()
+
+ + + +
+[docs] +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('-d', '--debug', action='store_true', dest='debug', help='increase logging verbosity') + parser.add_argument( + '-r', '--remote_devices', action='store_true', dest='remote_devices', help='show controls for remote devices' + ) + args = parser.parse_args() + + if args.debug: + setup_logger(name=None, level='DEBUG') + else: + setup_logger(name='iblrig', level='INFO') + QtCore.QCoreApplication.setOrganizationName('International Brain Laboratory') + QtCore.QCoreApplication.setOrganizationDomain('internationalbrainlab.org') + QtCore.QCoreApplication.setApplicationName('IBLRIG Wizard') + + if os.name == 'nt': + app_id = f'IBL.iblrig.wizard.{iblrig.__version__}' + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id) + app = QtWidgets.QApplication(['', '--no-sandbox']) + app.setStyle('Fusion') + w = RigWizard(debug=args.debug, remote_devices=args.remote_devices) + w.show() + app.exec()
+ + + +if __name__ == '__main__': + main() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/hardware.html b/_modules/iblrig/hardware.html new file mode 100644 index 000000000..8b6cd298b --- /dev/null +++ b/_modules/iblrig/hardware.html @@ -0,0 +1,641 @@ + + + + + + iblrig.hardware — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.hardware

+"""Hardware classes used to interact with modules."""
+
+import logging
+import os
+import re
+import shutil
+import struct
+import subprocess
+import threading
+import time
+from collections.abc import Callable
+from enum import IntEnum
+from pathlib import Path
+from typing import Annotated, Literal
+
+import numpy as np
+import serial
+import sounddevice as sd
+from annotated_types import Ge, Le
+from pydantic import PositiveFloat, PositiveInt, validate_call
+from serial.tools import list_ports
+
+from iblrig.tools import static_vars
+from iblutil.util import Bunch
+from pybpod_rotaryencoder_module.module import RotaryEncoder
+from pybpod_rotaryencoder_module.module_api import RotaryEncoderModule
+from pybpodapi.bpod.bpod_io import BpodIO
+from pybpodapi.bpod_modules.bpod_module import BpodModule
+from pybpodapi.state_machine import StateMachine
+
+SOFTCODE = IntEnum('SOFTCODE', ['STOP_SOUND', 'PLAY_TONE', 'PLAY_NOISE', 'TRIGGER_CAMERA'])
+
+# some annotated types
+Uint8 = Annotated[int, Ge(0), Le(255)]
+ActionIdx = Annotated[int, Ge(1), Le(255)]
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class Bpod(BpodIO): + can_control_led = True + softcodes: dict[int, Callable] | None = None + _instances = {} + _lock = threading.RLock() + _is_initialized = False + +
+[docs] + def __new__(cls, *args, **kwargs): + serial_port = args[0] if len(args) > 0 else '' + serial_port = kwargs.get('serial_port', serial_port) + with cls._lock: + instance = Bpod._instances.get(serial_port, None) + if instance: + return instance + instance = super().__new__(cls) + Bpod._instances[serial_port] = instance + return instance
+ + +
+[docs] + def __init__(self, *args, skip_initialization: bool = False, **kwargs): + # skip initialization if it has already been performed before + # IMPORTANT: only use this for non-critical tasks (e.g., flushing valve from GUI) + if skip_initialization and self._is_initialized: + return + + # try to instantiate once for nothing + try: + super().__init__(*args, **kwargs) + except Exception: + log.warning("Couldn't instantiate BPOD, retrying once...") + time.sleep(1) + try: + super().__init__(*args, **kwargs) + except (serial.serialutil.SerialException, UnicodeDecodeError) as e: + log.error(e) + raise serial.serialutil.SerialException( + 'The communication with Bpod is established but the Bpod is not responsive. ' + 'This is usually indicated by the device with a green light. ' + 'Please unplug the Bpod USB cable from the computer and plug it back in to start the task. ' + ) from e + self.serial_messages = {} + self.actions = Bunch({}) + self.can_control_led = self.set_status_led(True) + self._is_initialized = True
+ + +
+[docs] + def close(self) -> None: + super().close() + self._is_initialized = False
+ + + def __del__(self): + with self._lock: + if self.serial_port in Bpod._instances: + Bpod._instances.pop(self.serial_port) + + @property + def is_connected(self): + return self.modules is not None + + @property + def rotary_encoder(self): + return self.get_module('rotary_encoder') + + @property + def sound_card(self): + return self.get_module('sound_card') + + @property + def ambient_module(self): + return self.get_module('^AmbientModule') + +
+[docs] + def get_module(self, module_name: str) -> BpodModule | None: + """Get module by name. + + Parameters + ---------- + module_name : str + Regular Expression for matching a module name + + Returns + ------- + BpodModule | None + First matching module or None + """ + if self.modules is None: + return None + if module_name in ['re', 'rotary_encoder']: + module_name = r'^RotaryEncoder' + elif module_name in ['sc', 'sound_card']: + module_name = r'^SoundCard' + modules = [x for x in self.modules if re.match(module_name, x.name)] + if len(modules) > 1: + log.critical(f'Found several Bpod modules matching `{module_name}`. Using first match: `{modules[0].name}`') + if len(modules) > 0: + return modules[0]
+ + + @validate_call(config={'arbitrary_types_allowed': True}) + def _define_message(self, module: BpodModule | int, message: list[Uint8]) -> ActionIdx: + """Define a serial message to be sent to a Bpod module as an output action within a state. + + Parameters + ---------- + module : BpodModule | int + The targeted module, defined as a BpodModule instance or the module's port index + message : list[int] + The message to be sent - a list of up to three 8-bit integers + + Returns + ------- + int + The index of the serial message (1-255) + + Raises + ------ + TypeError + If module is not an instance of BpodModule or int + + Examples + -------- + >>> id_msg_bonsai_show_stim = self._define_message(self.rotary_encoder, [ord("#"), 2]) + will then be used as such in StateMachine: + >>> output_actions=[("Serial1", id_msg_bonsai_show_stim)] + """ + if isinstance(module, BpodModule): + module = module.serial_port + message_id = len(self.serial_messages) + 1 + self.load_serial_message(module, message_id, message) + self.serial_messages.update({message_id: {'target_module': module, 'message': message}}) + return message_id + +
+[docs] + @validate_call(config={'arbitrary_types_allowed': True}) + def define_xonar_sounds_actions(self): + self.actions.update( + { + 'play_tone': ('SoftCode', SOFTCODE.PLAY_TONE), + 'play_noise': ('SoftCode', SOFTCODE.PLAY_NOISE), + 'stop_sound': ('SoftCode', SOFTCODE.STOP_SOUND), + } + )
+ + +
+[docs] + def define_harp_sounds_actions(self, module: BpodModule, go_tone_index: int = 2, noise_index: int = 3) -> None: + module_port = f"Serial{module.serial_port if module is not None else ''}" + self.actions.update( + { + 'play_tone': (module_port, self._define_message(module, [ord('P'), go_tone_index])), + 'play_noise': (module_port, self._define_message(module, [ord('P'), noise_index])), + 'stop_sound': (module_port, ord('X')), + } + )
+ + +
+[docs] + def define_rotary_encoder_actions(self, module: BpodModule | None = None) -> None: + if module is None: + module = self.rotary_encoder + module_port = f"Serial{module.serial_port if module is not None else ''}" + self.actions.update( + { + 'rotary_encoder_reset': ( + module_port, + self._define_message(module, [RotaryEncoder.COM_SETZEROPOS, RotaryEncoder.COM_ENABLE_ALLTHRESHOLDS]), + ), + 'bonsai_hide_stim': (module_port, self._define_message(module, [ord('#'), 1])), + 'bonsai_show_stim': (module_port, self._define_message(module, [ord('#'), 8])), + 'bonsai_closed_loop': (module_port, self._define_message(module, [ord('#'), 3])), + 'bonsai_freeze_stim': (module_port, self._define_message(module, [ord('#'), 4])), + 'bonsai_show_center': (module_port, self._define_message(module, [ord('#'), 5])), + } + )
+ + +
+[docs] + def get_ambient_sensor_reading(self): + if self.ambient_module is None: + return { + 'Temperature_C': np.NaN, + 'AirPressure_mb': np.NaN, + 'RelativeHumidity': np.NaN, + } + self.ambient_module.start_module_relay() + self.bpod_modules.module_write(self.ambient_module, 'R') + reply = self.bpod_modules.module_read(self.ambient_module, 12) + self.ambient_module.stop_module_relay() + + return { + 'Temperature_C': np.frombuffer(bytes(reply[:4]), np.float32)[0], + 'AirPressure_mb': np.frombuffer(bytes(reply[4:8]), np.float32)[0] / 100, + 'RelativeHumidity': np.frombuffer(bytes(reply[8:]), np.float32)[0], + }
+ + +
+[docs] + def flush(self): + """Flushes valve 1.""" + self.toggle_valve()
+ + +
+[docs] + def toggle_valve(self, duration: int | None = None): + """ + Flush valve 1 for specified duration. + + Parameters + ---------- + duration : int, optional + Duration of valve opening in seconds. + """ + if duration is None: + self.open_valve(open=True, valve_number=1) + input('Press ENTER when done.') + self.open_valve(open=False, valve_number=1) + else: + self.pulse_valve(open_time_s=duration)
+ + +
+[docs] + def open_valve(self, open: bool, valve_number: int = 1): + self.manual_override(self.ChannelTypes.OUTPUT, self.ChannelNames.VALVE, valve_number, open)
+ + +
+[docs] + def pulse_valve(self, open_time_s: float, valve: str = 'Valve1'): + sma = StateMachine(self) + sma.add_state( + state_name='flush', state_timer=open_time_s, state_change_conditions={'Tup': 'exit'}, output_actions=[(valve, 255)] + ) + self.send_state_machine(sma) + self.run_state_machine(sma)
+ + +
+[docs] + @validate_call() + def pulse_valve_repeatedly( + self, repetitions: PositiveInt, open_time_s: PositiveFloat, close_time_s: PositiveFloat = 0.2, valve: str = 'Valve1' + ) -> int: + counter = 0 + + def softcode_handler(softcode: int): + nonlocal counter, repetitions + if softcode == 1: + counter += 1 + elif softcode == 2 and counter >= repetitions: + self.stop_trial() + + original_softcode_handler = self.softcode_handler_function + self.softcode_handler_function = softcode_handler + + sma = StateMachine(self) + sma.add_state( + state_name='open', + state_timer=open_time_s, + state_change_conditions={'Tup': 'close'}, + output_actions=[(valve, 255), ('SoftCode', 1)], + ) + sma.add_state( + state_name='close', + state_timer=close_time_s, + state_change_conditions={'Tup': 'open'}, + output_actions=[('SoftCode', 2)], + ) + self.send_state_machine(sma) + self.run_state_machine(sma) + + self.softcode_handler_function = original_softcode_handler + return counter
+ + +
+[docs] + @static_vars(supported=True) + def set_status_led(self, state: bool) -> bool: + if self.can_control_led and self._arcom is not None: + try: + log.debug(f'{"en" if state else "dis"}abling Bpod Status LED') + command = struct.pack('cB', b':', state) + self._arcom.serial_object.write(command) + if self._arcom.read_uint8() == 1: + return True + except serial.SerialException: + pass + self._arcom.serial_object.reset_input_buffer() + self._arcom.serial_object.reset_output_buffer() + log.warning('Bpod device does not support control of the status LED. Please update firmware.') + return False
+ + +
+[docs] + def valve(self, valve_id: int, state: bool): + self.manual_override(self.ChannelTypes.OUTPUT, self.ChannelNames.VALVE, valve_id, state)
+ + +
+[docs] + @validate_call + def register_softcodes(self, softcode_dict: dict[int, Callable]) -> None: + """ + Register softcodes to be used in the state machine. + + Parameters + ---------- + softcode_dict : dict[int, Callable] + dictionary of int keys with callables as values + """ + self.softcodes = softcode_dict + self.softcode_handler_function = lambda code: softcode_dict[code]()
+
+ + + +
+[docs] +class MyRotaryEncoder: +
+[docs] + def __init__(self, all_thresholds, gain, com, connect=False): + self.RE_PORT = com + self.WHEEL_PERIM = 31 * 2 * np.pi # = 194,778744523 + self.deg_mm = 360 / self.WHEEL_PERIM + self.mm_deg = self.WHEEL_PERIM / 360 + self.factor = 1 / (self.mm_deg * gain) + self.SET_THRESHOLDS = [x * self.factor for x in all_thresholds] + self.ENABLE_THRESHOLDS = [(x != 0) for x in self.SET_THRESHOLDS] + # ENABLE_THRESHOLDS needs 8 bools even if only 2 thresholds are set + while len(self.ENABLE_THRESHOLDS) < 8: + self.ENABLE_THRESHOLDS.append(False) + + # Names of the RE events generated by Bpod + self.ENCODER_EVENTS = [f'RotaryEncoder1_{x}' for x in list(range(1, len(all_thresholds) + 1))] + # Dict mapping threshold crossings with name ov RE event + self.THRESHOLD_EVENTS = dict(zip(all_thresholds, self.ENCODER_EVENTS, strict=False)) + if connect: + self.connect()
+ + +
+[docs] + def connect(self): + if self.RE_PORT == 'COM#': + return + m = RotaryEncoderModule(self.RE_PORT) + m.set_zero_position() # Not necessarily needed + m.set_thresholds(self.SET_THRESHOLDS) + m.enable_thresholds(self.ENABLE_THRESHOLDS) + m.enable_evt_transmission() + m.close()
+
+ + + +
+[docs] +def sound_device_factory(output: Literal['xonar', 'harp', 'hifi', 'sysdefault'] = 'sysdefault', samplerate: int | None = None): + """ + Will import, configure, and return sounddevice module to play sounds using onboard sound card. + + Parameters + ---------- + output + defaults to "sysdefault", should be 'xonar' or 'harp' + samplerate + audio sample rate, defaults to 44100 + """ + match output: + case 'xonar': + samplerate = samplerate if samplerate is not None else 192000 + devices = sd.query_devices() + sd.default.device = next((i for i, d in enumerate(devices) if 'XONAR SOUND CARD(64)' in d['name']), None) + sd.default.latency = 'low' + sd.default.channels = 2 + channels = 'L+TTL' + sd.default.samplerate = samplerate + case 'harp': + samplerate = samplerate if samplerate is not None else 96000 + sd.default.samplerate = samplerate + sd.default.channels = 2 + channels = 'stereo' + case 'hifi': + samplerate = samplerate if samplerate is not None else 192000 + channels = 'stereo' + case 'sysdefault': + samplerate = samplerate if samplerate is not None else 44100 + sd.default.latency = 'low' + sd.default.channels = 2 + sd.default.samplerate = samplerate + channels = 'stereo' + case _: + raise ValueError() + return sd, samplerate, channels
+ + + +
+[docs] +def restart_com_port(regexp: str) -> bool: + """ + Restart the communication port(s) matching the specified regular expression. + + Parameters + ---------- + regexp : str + A regular expression used to match the communication port(s). + + Returns + ------- + bool + Returns True if all matched ports are successfully restarted, False otherwise. + + Raises + ------ + NotImplementedError + If the operating system is not Windows. + + FileNotFoundError + If the required 'pnputil.exe' executable is not found. + + Examples + -------- + >>> restart_com_port("COM3") # Restart the communication port with serial number 'COM3' + True + + >>> restart_com_port("COM[1-3]") # Restart communication ports with serial numbers 'COM1', 'COM2', 'COM3' + True + """ + if not os.name == 'nt': + raise NotImplementedError('Only implemented for Windows OS.') + if not (file_pnputil := Path(shutil.which('pnputil'))).exists(): + raise FileNotFoundError('Could not find pnputil.exe') + result = [] + for port in list_ports.grep(regexp): + pnputil_output = subprocess.check_output([file_pnputil, '/enum-devices', '/connected', '/class', 'ports']) + instance_id = re.search(rf'(\S*{port.serial_number}\S*)', pnputil_output.decode()) + if instance_id is None: + continue + result.append( + subprocess.check_call( + [file_pnputil, '/restart-device', f'"{instance_id.group}"'], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT + ) + == 0 + ) + return all(result)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/hardware_validation.html b/_modules/iblrig/hardware_validation.html new file mode 100644 index 000000000..5f6ed32d0 --- /dev/null +++ b/_modules/iblrig/hardware_validation.html @@ -0,0 +1,1065 @@ + + + + + + iblrig.hardware_validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.hardware_validation

+import logging
+import re
+from abc import ABC, abstractmethod
+from collections.abc import Generator
+from dataclasses import dataclass
+from datetime import date
+from enum import IntEnum
+from inspect import isabstract
+from math import isclose
+from struct import unpack
+from typing import Any, cast
+
+import numpy as np
+import sounddevice
+import usb
+from dateutil.relativedelta import relativedelta
+from PyQt5.QtGui import QColorConstants
+from PyQt5.QtWidgets import QApplication
+from serial import Serial, SerialException
+from serial.serialutil import SerialTimeoutException
+from serial.tools import list_ports
+from serial.tools.list_ports_common import ListPortInfo
+
+from iblrig.base_tasks import BpodMixin, SoundMixin
+from iblrig.constants import BASE_PATH, HAS_PYSPIN, HAS_SPINNAKER, IS_GIT
+from iblrig.frame2ttl import Frame2TTL
+from iblrig.hardware import Bpod
+from iblrig.path_helper import load_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings
+from iblrig.serial_singleton import SerialSingleton, filter_ports
+from iblrig.tools import ANSI, get_inheritors, internet_available
+from iblrig.version_management import get_branch, is_dirty
+from pybpodapi.bpod_modules.bpod_module import BpodModule
+from pybpodapi.state_machine import StateMachine
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class Status(IntEnum): + """Possible status codes of hardware validations.""" + + PEND = 0 # Test pending + SKIP = 1 # Test not applicable (e.g., device not present) + PASS = 2 # Test passed + WARN = 3 # Test passed with warning + INFO = 4 # Secondary information yielded from tests (e.g., firmware version) + FAIL = 5 # Test failed
+ + + +
+[docs] +@dataclass +class Result: + """Dataclass holding the results of a single validation.""" + + status: Status + message: str + ext_message: str | None = None + solution: str | None = None + url: str | None = None + exception: Exception | None = None
+ + + +
+[docs] +class ValidateHardwareError(Exception): + def __init__(self, results: Result): + super().__init__(results.message) + self.results = results
+ + + +
+[docs] +class Validator(ABC): + log_results: bool = True + raise_fail_as_exception: bool = False + interactive: bool + iblrig_settings: RigSettings + hardware_settings: HardwareSettings + _name: str | None = None + +
+[docs] + def __init__( + self, + iblrig_settings: RigSettings | None = None, + hardware_settings: HardwareSettings | None = None, + interactive: bool = False, + ): + self.iblrig_settings = iblrig_settings or load_pydantic_yaml(RigSettings) + self.hardware_settings = hardware_settings or load_pydantic_yaml(HardwareSettings) + self.interactive = interactive
+ + + @property + def name(self) -> str: + return getattr(self, '_name', self.__class__.__name__) + + @abstractmethod + def _run(self, *args, **kwargs) -> Generator[Result, None, bool]: ... + +
+[docs] + def run(self, *args, **kwargs) -> Generator[Result, None, bool]: + success = yield from self._run(*args, **kwargs) + return success
+ + + def _get_bpod(self) -> Generator[Result, None, Bpod | None]: + if self.hardware_settings.device_bpod.COM_BPOD is None: + yield Result(Status.WARN, f'Cannot complete validation of {self.name} without Bpod') + return None + try: + disabled_ports = [x - 1 for x in self.hardware_settings['device_bpod']['DISABLE_BEHAVIOR_INPUT_PORTS']] + return Bpod( + self.hardware_settings.device_bpod.COM_BPOD, skip_initialization=True, disable_behavior_ports=disabled_ports + ) + except Exception as e: + yield Result(Status.FAIL, f'Cannot complete validation of {self.name}: connection to Bpod failed', exception=e) + return None + + def _get_module(self, module_name: str, bpod: Bpod | None = None) -> Generator[Result, None, BpodModule | None]: + if bpod is None: + bpod = yield from self._get_bpod() + if bpod is None: + return None + + module = None if bpod.modules is None else next((m for m in bpod.modules if m.name.startswith(module_name)), None) + + if module is not None: + yield Result(Status.PASS, f'{self.name} is connected to Bpod on module port #{module.serial_port}') + yield Result(Status.INFO, f'Firmware Version: {module.firmware_version}') + return module + else: + yield Result( + Status.FAIL, + f"{self.name} is not connected to Bpod's module port", + solution=f"Connect {self.name} to one of Bpod's module ports", + ) + return None + +
+[docs] + def process(self, results: Result) -> Result: + if self.log_results: + match results.status: + case Status.PASS: + log_level = logging.INFO + case Status.INFO: + log_level = logging.INFO + case Status.FAIL: + log_level = logging.CRITICAL + case _: + log_level = logging.CRITICAL + log.log(log_level, results.message) + + if self.raise_fail_as_exception and results.status == Status.FAIL: + if results.exception is not None: + raise ValidateHardwareError(results) from results.exception + else: + raise ValidateHardwareError(results) + + return results
+
+ + + +
+[docs] +class ValidatorSerial(Validator): + port_properties: dict[str, Any] = {} + serial_queries: None | dict[tuple[bytes, int], bytes] = None + +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs)
+ + + @property + @abstractmethod + def port(self) -> str | None: ... + + @property + def port_info(self) -> ListPortInfo | None: + return next(list_ports.grep(self.port), None) if self.port is not None else None + + def _run(self): + if self.port is None: + yield Result( + Status.FAIL, + f'No serial port defined for {self.name}', + solution='Check serial port setting in hardware_settings.yaml', + ) + return False + elif next((p for p in list_ports.comports() if p.device == self.port), None) is None: + yield Result( + Status.FAIL, + f'{self.port} is not a valid serial port', + solution='Check serial port setting in hardware_settings.yaml', + ) + return False + else: + try: + Serial(self.port, timeout=1).close() + yield Result(Status.PASS, f'Serial device on {self.port} can be connected to') + yield Result( + Status.INFO, + f'USB ID: {self.port_info.vid:04X}:{self.port_info.pid:04X}, ' + f'Serial Number: {self.port_info.serial_number}', + ) + except SerialException as e: + yield Result( + Status.FAIL, + f'Serial device on {self.port} cannot be connected to', + solution='Try power-cycling the device', + exception=e, + ) + return False + + # first, test for properties of the serial port without opening the latter (VID, PID, etc) + passed = ( + self.port in filter_ports(**self.port_properties) if getattr(self, 'port_properties', None) is not None else False + ) + + # query the devices for characteristic responses + if passed and getattr(self, 'serial_queries', None) is not None: + with Serial(self.port, timeout=1, write_timeout=1) as ser: + try: + for query, regex_pattern in self.serial_queries.items(): + ser.write(query[0]) + return_string = ser.read(query[1]) + ser.flush() + if not (passed := bool(re.search(regex_pattern, return_string))): + break + except SerialTimeoutException as e: + yield Result( + Status.FAIL, + f'Writing to serial device on {self.port} timed out', + solution='Try power-cycling the device', + exception=e, + ) + return False + + if passed: + yield Result(Status.PASS, f'Serial device positively identified as {self.name}') + return True + else: + yield Result( + Status.FAIL, + f'Serial device on {self.port} does NOT seem to be a {self.name}', + solution='Check serial port setting in hardware_settings.yaml', + ) + return False
+ + + +
+[docs] +class ValidatorRotaryEncoderModule(ValidatorSerial): + _name = 'Bpod Rotary Encoder Module' + port_properties = {'vid': 0x16C0} + serial_queries = {(b'Q', 2): b'^..$', (b'P00', 1): b'\x01'} + + @property + def port(self): + return self.hardware_settings.device_rotary_encoder.COM_ROTARY_ENCODER + + def _run(self): + # invoke ValidateSerialDevice._run() + success = yield from super()._run() + if not success: + return False + + # obtain hardware version + with SerialSingleton(self.port, timeout=0.1) as ser: + v = '1.x' if ser.query(b'Ix', 1) == b'\x01' else '2+' + yield Result(Status.INFO, f'Hardware Version: {v}') + + # try to get Bpod + bpod = yield from self._get_bpod() + if not bpod: + return False + + # try to get Bpod module + module = yield from self._get_module('RotaryEncoder', bpod) + if not module: + return False
+ + + # log_fun('info', f'firmware version: {bpod.modules[0].firmware_version}') + # + # s.write(b'Z') + # p = np.frombuffer(query(s, b'Q', 2), dtype=np.int16)[0] + # log_fun('warn', "please move the wheel to the left (animal's POV) by a quarter turn") + # while np.abs(p) < 200: + # p = np.frombuffer(query(s, b'Q', 2), dtype=np.int16)[0] + # if p > 0: + # log_fun('fail', 'Rotary encoder seems to be wired incorrectly - try swapping A and B', last=True) + # else: + # log_fun('pass', 'rotary encoder is wired correctly', last=True) + # s.close() + + +# class ValidatorScreen(Validator): +# device_name = 'Screen' +# +# def _run(self): +# pass +# # if os.name == 'nt': +# # import ctypes +# # +# # from win32api import EnumDisplayMonitors, EnumDisplaySettingsEx, GetMonitorInfo +# # +# # display_idx = self.hardware_settings.device_screen.DISPLAY_IDX +# # monitors = EnumDisplayMonitors() +# # monitor = monitors[display_idx] +# # display_handle = monitor[0] +# # scale_factor = ctypes.windll.shcore.GetScaleFactorForDevice(display_idx) +# # display_info = GetMonitorInfo(display_handle) +# # display_settings = EnumDisplaySettingsEx(display_info['Device']) +# # # TODO: Implementation ... + + +
+[docs] +class ValidatorAmbientModule(Validator): + _name = 'Bpod Ambient Module' + + def _run(self): + # yield Bpod's connection status + bpod = yield from self._get_bpod() + if bpod is None: + return False + + # yield module's connection status + module = yield from self._get_module('AmbientModule', bpod) + if module is None: + return False + + # yield sensor values + module.start_module_relay() + bpod.bpod_modules.module_write(module, 'R') + (t, p, h) = unpack('3f', bytes(bpod.bpod_modules.module_read(module, 12))) + module.stop_module_relay() + yield Result(Status.INFO, f'Temperature: {t:.1f} °C') + yield Result(Status.INFO, f'Air pressure: {p / 100:.1f} mbar') + yield Result(Status.INFO, f'Rel. humidity: {h:.1f}%') + return True
+ + + +
+[docs] +class ValidatorBpod(ValidatorSerial): + _name = 'Bpod' + port_properties = {'vid': 0x16C0} + serial_queries = {(b'6', 1): b'5'} + + @property + def port(self): + return self.hardware_settings.device_bpod.COM_BPOD + + def _run(self): + # close existing Bpod singleton + if (bpod := Bpod._instances.get(self.hardware_settings.device_bpod.COM_BPOD, None)) is not None: # noqa + bpod.close() + + # invoke ValidateSerialDevice._run() + success = yield from super()._run() + if not success: + return False + + # check hardware and firmware version + with SerialSingleton(self.hardware_settings.device_bpod.COM_BPOD) as ser: + v_major, machine_type = ser.query(b'F', '<2H') + firmware_version = (v_major, ser.query(b'f', '<H')[0] if v_major > 22 else 0) + machine_str = {1: 'v0.5', 2: 'r07+', 3: 'r2.0-2.5', 4: '2+ r1.0'}[machine_type] + machine_str.join(f", PCB revision{ser.query(b'v', '<B')[0]}" if v_major > 22 else '') + yield Result(Status.INFO, f'Hardware version: {machine_str}') + yield Result(Status.INFO, f'Firmware version: {firmware_version[0]}.{firmware_version[1]}') + if firmware_version[0] > 22: + yield Result( + Status.FAIL, + 'Firmware version greater than 22 are not supported by IBLRIG', + solution='Downgrade the Bpod' 's firmware to version 22', + ) + return False + + # try to connect to Bpod + try: + disabled_ports = [x - 1 for x in self.hardware_settings['device_bpod']['DISABLE_BEHAVIOR_INPUT_PORTS']] + bpod = Bpod( + self.hardware_settings.device_bpod.COM_BPOD, skip_initialization=False, disable_behavior_ports=disabled_ports + ) + yield Result(Status.PASS, 'Successfully connected to Bpod using pybpod') + except Exception as e: + yield Result( + Status.FAIL, 'Could not connect to Bpod using pybpod', solution='Try power-cycling the Bpod', exception=e + ) + return False + + # return connected modules + for module in bpod.modules: + if module.connected: + yield Result(Status.INFO, f'Module on port #{module.serial_port}: "{module.name}"') + + # run a simple state machine to collect events on digital inputs + try: + sma = StateMachine(bpod) + sma.add_state(sma.add_state('state', 0.2, {'Tup': 'exit'})) + bpod.send_state_machine(sma) + bpod.run_state_machine(sma) + bpod_data = bpod.session.current_trial.export() + events: dict[str, list[float]] = bpod_data.get('Events timestamps', {}) + except Exception as e: + yield Result(Status.FAIL, 'Error running state-machine', exception=e) + return False + + # check for (un)expected input events + for event_name, timestamps in sorted(events.items()): + if event_name.endswith('Out') or event_name.endswith('Low') or event_name == 'Tup': + continue + rate = np.mean(1 / np.diff(timestamps)) + port = re.sub('(In)|(High)', '', event_name) + port = re.sub('Port', 'Behavior Port ', port) + port = re.sub('BNC', 'BNC Input ', port) + if event_name in ['Port1In']: + yield Result(Status.INFO, f"Expected input events on Bpod's '{port}' at ~{rate:0.0f} Hz") + else: + yield Result( + Status.FAIL, + f"Unexpected input events on Bpod's '{port}' at ~{rate:0.0f} Hz", + solution=f"Check wiring / device connected on '{port}'.", + ) + + return True
+ + + +
+[docs] +class ValidatorCamera(Validator): + _name = 'Camera' + + def _run(self): + if self.hardware_settings.device_cameras is None or ( + isinstance(self.hardware_settings.device_cameras, dict) and len(self.hardware_settings.device_cameras) == 0 + ): + yield Result(Status.SKIP, 'No cameras defined in hardware_settings.yaml - skipping validation') + return False + + if HAS_SPINNAKER: + yield Result(Status.PASS, 'Spinnaker SDK is installed') + else: + yield Result( + Status.WARN, 'Spinnaker SDK is not installed', solution='Use install_spinnaker command to install Spinnaker SDK' + ) + + if HAS_PYSPIN: + yield Result(Status.PASS, 'PySpin is installed') + else: + yield Result(Status.WARN, 'PySpin is not installed', solution='Use install_pyspin command to install PySpin') + + if HAS_SPINNAKER and HAS_PYSPIN: + from iblrig.video_pyspin import Cameras, enable_camera_trigger + + with Cameras() as cameras: + if len(cameras) == 0: + yield Result( + Status.FAIL, + 'Could not find a camera connected to the computer', + solution='Connect a camera on one of the computers USB ports', + ) + return False + else: + yield Result( + Status.PASS, f'Found {len(cameras)} camera{"s" if len(cameras) > 1 else ""} connected to the computer' + ) + for idx in range(len(cameras)): + yield Result( + Status.INFO, + f'Camera {idx}: {cameras[idx].DeviceModelName.ToString()}, ' + f'Serial #{cameras[idx].DeviceID.ToString()}', + ) + enable_camera_trigger(enable=False, camera=cameras[idx]) + + # yield Bpod's connection status + bpod = yield from self._get_bpod() + if bpod is None: + return False + + sma = StateMachine(bpod) + sma.add_state(state_name='collect', state_timer=0.2, state_change_conditions={'Tup': 'exit'}) + bpod.send_state_machine(sma) + bpod.run_state_machine(sma) + triggers = [i.host_timestamp for i in bpod.session.current_trial.events_occurrences if i.content == 'Port1In'] + if len(triggers) == 0: + yield Result( + Status.FAIL, + "No TTL detected on Bpod's behavior port #1", + solution='Check the wiring between camera and valve driver board and make sure the latter is connected ' + "to Bpod's behavior port #1", + ) + return False + else: + yield Result(Status.PASS, "Detected camera TTL on Bpod's behavior port #1") + trigger_rate = np.mean(1 / np.diff(triggers)) + target_rate = 30 + if isclose(trigger_rate, target_rate, rel_tol=0.1): + yield Result(Status.PASS, f'Measured TTL rate: {trigger_rate:.1f} Hz') + else: + yield Result(Status.WARN, f'Measured TTL rate: {trigger_rate:.1f} Hz (expecting {target_rate} Hz)') + return True
+ + + +
+[docs] +class ValidatorAlyx(Validator): + _name = 'Alyx' + + def _run(self): + # Validate ALYX_URL + if self.iblrig_settings.ALYX_URL is None: + yield Result(Status.SKIP, 'ALYX_URL has not been set in hardware_settings.yaml - skipping validation') + return False + elif not internet_available(timeout=2, force_update=True): + yield Result( + Status.FAIL, f'Cannot connect to {self.iblrig_settings.ALYX_URL.host}', solution='Check your Internet connection' + ) + return False + elif not internet_available(host=self.iblrig_settings.ALYX_URL.host, port=443, timeout=2, force_update=True): + yield Result( + Status.FAIL, + f'Cannot connect to {self.iblrig_settings.ALYX_URL.host}', + solution='Check ALYX_URL in hardware_settings.yaml and make sure that your computer is allowed to connect', + ) + return False + else: + yield Result(Status.PASS, f'{self.iblrig_settings.ALYX_URL.host} can be connected to') + + # Validate ALYX_LAB + if self.iblrig_settings.ALYX_LAB is None: + yield Result(Status.FAIL, 'ALYX_LAB has not been set', solution='Set ALYX_LAB in hardware_settings.yaml') + return True
+ + + +
+[docs] +class ValidatorValve(Validator): + _name = 'Valve' + + def _run(self): + calibration_date = self.hardware_settings.device_valve.WATER_CALIBRATION_DATE + today = date.today() + delta_warn = relativedelta(months=1) + delta_fail = relativedelta(months=3) + days_passed = (today - calibration_date).days + if calibration_date > date.today(): + yield Result(Status.FAIL, 'Date of last valve calibration is in the future', solution='Calibrate valve') + elif calibration_date + delta_warn < today: + yield Result(Status.WARN, f'Valve has not been calibrated in {days_passed} days', solution='Calibrate valve') + elif calibration_date + delta_fail < date.today(): + yield Result(Status.FAIL, f'Valve has not been calibrated in {days_passed} days', solution='Calibrate valve') + elif days_passed > 1: + yield Result(Status.PASS, f'Valve has been calibrated {days_passed} days ago') + else: + yield Result(Status.PASS, f'Valve has been calibrated {"yesterday" if days_passed==1 else "today"}')
+ + + +
+[docs] +class ValidatorMic(Validator): + _name = 'Microphone' + + def _run(self): + if self.hardware_settings.device_microphone is None: + yield Result(Status.SKIP, 'No workflow defined for microphone') + return False + + sounddevice._terminate() + sounddevice._initialize() + + devices = [d for d in sounddevice.query_devices() if 'UltraMic 200K' in d.get('name', '')] + if len(devices) > 0: + yield Result(Status.PASS, 'Found UltraMic 200K microphone') + return True + else: + yield Result( + Status.FAIL, + 'Could not find UltraMic 200K microphone', + solution='Make sure that the microphone is connected to the PC via USB', + ) + return False
+ + + +
+[docs] +class ValidatorFrame2TTL(ValidatorSerial): + _name = 'Frame2TTL' + serial_queries = {(b'C', 1): b'\xda'} + + @property + def port(self): + return self.hardware_settings.device_frame2ttl.COM_F2TTL + + def _run(self): + # invoke ValidateSerialDevice._run() + success = yield from super()._run() + if not success: + return False + + # obtain information on versions and thresholds + with Frame2TTL( + port=self.port, + threshold_light=self.hardware_settings.device_frame2ttl.F2TTL_LIGHT_THRESH, + threshold_dark=self.hardware_settings.device_frame2ttl.F2TTL_DARK_THRESH, + ) as frame2ttl: + yield Result(Status.INFO, f'Hardware Version: {frame2ttl.hw_version}') + yield Result(Status.INFO, f'Firmware Version: {frame2ttl.fw_version}') + yield Result(Status.INFO, f'Light Threshold: {frame2ttl.threshold_light} {frame2ttl.unit_str}') + yield Result(Status.INFO, f'Dark Threshold: {frame2ttl.threshold_dark} {frame2ttl.unit_str}') + + # try to get Bpod + bpod = yield from self._get_bpod() + if bpod is None: + return False + + # prepare test of TTL output + from iblrig.gui.frame2ttl import Frame2TTLCalibrationTarget + + app = QApplication.instance() + if app_created := app is None: + app = QApplication([]) + calibration_target = Frame2TTLCalibrationTarget(color=QColorConstants.Black) + calibration_target.show() + + # Define state-machine + def softcode_handler(softcode: int): + nonlocal calibration_target + calibration_target.color = QColorConstants.White if softcode == 1 else QColorConstants.Black + + original_softcode_handler = bpod.softcode_handler_function + bpod.softcode_handler_function = softcode_handler + sma = StateMachine(bpod) + sma.add_state( + state_name='white', + state_timer=1, + state_change_conditions={'Tup': 'black', 'BNC1High': 'black'}, + output_actions=[('SoftCode', 1)], + ) + sma.add_state( + state_name='black', + state_timer=1, + state_change_conditions={'Tup': 'exit', 'BNC1Low': 'exit'}, + output_actions=[('SoftCode', 2)], + ) + + # Run state-machine + try: + bpod.send_state_machine(sma) + bpod.run_state_machine(sma) + bpod_data = bpod.session.current_trial.export() + events: dict[str, list[float]] = bpod_data.get('Events timestamps', {}) + except Exception as e: + yield Result(Status.FAIL, 'Error running state-machine', exception=e) + return False + finally: + bpod.softcode_handler_function = original_softcode_handler + calibration_target.close() + if app_created: + app.quit() + + # Evaluate results + if (n_events := len(events.get('BNC1High', [])) + len(events.get('BNC1Low', []))) == 2: + yield Result(Status.PASS, "Detected the correct number of events on Bpod's 'TTL Input 1'") + return True + else: + yield Result( + Status.FAIL, + ('No' if n_events == 0 else 'too few' if n_events < 2 else 'too many') + + " events detected on Bpod's 'BNC Input 1'", + solution='Check for proper installation and calibration of Frame2TTL module', + ) + return False
+ + + +
+[docs] +class ValidatorGit(Validator): + _name = 'Git' + + def _run(self): + if not IS_GIT: + yield Result(Status.SKIP, 'Your copy of IBLRIG is not managed through Git') + return False + + return_status = True + main_branch = 'iblrigv8' + this_branch = get_branch() + if this_branch != main_branch: + yield Result( + Status.WARN, + f"Working tree of IBLRIG is on Git branch '{this_branch}'", + solution=f"Issue 'git checkout {main_branch}' to switch to '{main_branch}' branch", + ) + return_status = False + else: + yield Result(Status.PASS, f"Working tree of IBLRIG is on Git branch '{main_branch}'") + + if is_dirty(): + yield Result( + Status.WARN, + "Working tree of IBLRIG contains local changes - don't expect things to work as intended!", + solution="To list files that have been changed locally, issue 'git diff --name-only'. " + "Issue 'git reset --hard' to reset the repository to its default state", + ) + return_status = False + else: + yield Result(Status.PASS, 'Working tree of IBLRIG does not contain local changes') + + return return_status
+ + + +class _SoundCheckTask(BpodMixin, SoundMixin): + protocol_name = 'hardware_check_harp' + + def __init__(self, *args, **kwargs): + param_file = BASE_PATH.joinpath('iblrig', 'base_choice_world_params.yaml') + super().__init__(*args, task_parameter_file=param_file, **kwargs) + + def start_hardware(self): + self.start_mixin_bpod() + self.start_mixin_sound() + + def get_state_machine(self): + sma = StateMachine(self.bpod) + sma.add_state('tone', 0.5, {'Tup': 'exit'}, [self.bpod.actions.play_tone]) + return sma + + def _run(self): + pass + + def create_session(self): + pass + + def send_spacers(self): + pass + + +
+[docs] +class ValidatorSound(ValidatorSerial): + _name = 'Sound' + _module_name: str | None = None + +
+[docs] + def __init__(self, *args, **kwargs): + output_type = kwargs['hardware_settings'].device_sound.OUTPUT + match output_type: + case 'harp': + self._name = 'HARP Sound Card' + self._module_name = 'SoundCard' + self.port_properties = {'vid': 0x0403, 'pid': 0x6001} + case 'hifi': + self._name = 'Bpod HiFi Module' + self._module_name = 'HiFi' + self.serial_queries = {(b'\xf3', 1): b'\xf4'} + self.port_properties = {'vid': 0x16C0, 'pid': 0x0483} + case 'xonar': + self._name = 'Xonar Sound Card' + if output_type in ['harp', 'hifi']: + super().__init__(*args, **kwargs) # call ValidatorSerial.__init__() + else: + super(ValidatorSerial, self).__init__(*args, **kwargs) # call Validator.__init__()
+ + + @property + def port(self) -> str | None: + match self.hardware_settings.device_sound.OUTPUT: + case 'harp': + return ( + com_port + if (com_port := self.hardware_settings.device_sound.COM_SOUND) is not None + else next(filter_ports(**self.port_properties), None) + ) + case 'hifi': + return self.hardware_settings.device_sound.COM_SOUND + case _: + return None + + def _run(self): + if (success := self.hardware_settings.device_sound.OUTPUT) == 'sysdefault': + yield Result( + Status.FAIL, + "Sound output device 'sysdefault' is intended for testing purposes only", + solution="Set device_sound.OUTPUT to 'hifi', 'harp' or 'xonar'", + ) + return False + + # check serial device + if self.hardware_settings.device_sound.OUTPUT in ['harp', 'hifi']: + success = yield from super()._run() + if not success: + return False + + # device-specific validations + match self.hardware_settings.device_sound.OUTPUT: + case 'harp': + if (dev := usb.core.find(manufacturer='Champalimaud Foundation', product='Harp Sound Card')) is None: + yield Result( + Status.FAIL, + 'Cannot find USB sound device', + solution="Connect both of the sound card's USB ports and make sure that the HARP drivers are " + 'installed', + ) + return False + else: + yield Result(Status.PASS, 'Found USB sound device') + yield Result(Status.INFO, f'USB ID: {dev.idVendor:04X}:{dev.idProduct:04X}') + + # yield module's connection status + if self._module_name is not None: + module = yield from self._get_module(self._module_name) + if module is None: + return False + + # run state machine + if self.interactive: + logging.disable(logging.INFO) + task = _SoundCheckTask(subject='toto') + task.start_hardware() + sma = task.get_state_machine() + task.bpod.send_state_machine(sma) + yield Result(Status.INFO, 'Playing audible sound - can you hear it?') + task.bpod.run_state_machine(sma) + logging.disable(logging.NOTSET) + bpod_data = task.bpod.session.current_trial.export() + if (n_events := len(bpod_data['Events timestamps'].get('BNC2High', []))) == 0: + yield Result( + Status.FAIL, + "No event detected on Bpod's BNC In 2", + solution="Make sure to connect the sound-card to Bpod's TTL Input 2", + ) + elif n_events == 1: + yield Result(Status.PASS, "Detected Event on Bpod's 'TTL Input 2'") + else: + yield Result( + Status.FAIL, + "Multiple events detected on Bpod's BNC Input 2", + solution="Make sure to connect the sound-card to Bpod's TTL Input 2", + )
+ + + +
+[docs] +def get_all_validators() -> list[type[Validator]]: + return [cast(type[Validator], x) for x in get_inheritors(Validator) if not isabstract(x)]
+ + + +
+[docs] +def run_all_validators( + iblrig_settings: RigSettings | None = None, hardware_settings: HardwareSettings | None = None, interactive: bool = False +) -> Generator[Result, None, None]: + validators = get_all_validators() + for validator in validators: + yield from validator(iblrig_settings=iblrig_settings, hardware_settings=hardware_settings, interactive=interactive).run()
+ + + +
+[docs] +def run_all_validators_cli(): + validators = get_all_validators() + hardware_settings = load_pydantic_yaml(HardwareSettings) + iblrig_settings = load_pydantic_yaml(RigSettings) + fail = 0 + warn = 0 + for validator in validators: + v = validator(hardware_settings=hardware_settings, iblrig_settings=iblrig_settings, interactive=True) + print(f'{ANSI.BOLD + ANSI.UNDERLINE + v.name + ANSI.END}') + for result in v.run(): + match result.status: + case Status.PASS: + color = ANSI.GREEN + symbol = '✓' + case Status.FAIL: + color = ANSI.RED + ANSI.BOLD + fail += 1 + symbol = '✗' + case Status.WARN: + color = ANSI.YELLOW + ANSI.BOLD + warn += 1 + symbol = '!' + case Status.INFO: + color = ANSI.BLUE + symbol = 'i' + case Status.SKIP: + color = ANSI.WHITE + symbol = '∅' + case _: + color = ANSI.END + symbol = '?' + print(f'{color} {symbol} {result.message}{ANSI.END}') + if result.solution is not None and len(result.solution) > 0: + print(f'{color} Suggestion: {result.solution}{ANSI.END}') + print('') + if fail > 0: + print(ANSI.RED + ANSI.BOLD + f'{fail} validation{"s" if fail > 1 else ""} failed.') + if warn > 0: + print(ANSI.YELLOW + ANSI.BOLD + f'Validations passed with {warn} warning{"s" if warn > 1 else ""}.') + if warn == 0 and fail == 0: + print(ANSI.GREEN + ANSI.BOLD + 'All validations were passed - no issues found.')
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/hifi.html b/_modules/iblrig/hifi.html new file mode 100644 index 000000000..1ff8edcfd --- /dev/null +++ b/_modules/iblrig/hifi.html @@ -0,0 +1,310 @@ + + + + + + iblrig.hifi — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.hifi

+import logging
+from dataclasses import dataclass
+
+import numpy as np
+from pydantic import validate_call
+
+from iblrig.serial_singleton import SerialSingleton, SerialSingletonException
+
+log = logging.getLogger(__name__)
+
+
+@dataclass
+class _HiFiInfo:
+    is_hd: bool
+    bit_depth: int
+    max_waves: int
+    digital_attenuation: int
+    sampling_rate_hz: int
+    max_seconds_per_waveform: int
+    max_envelope_size: int
+
+
+
+[docs] +class HiFiException(SerialSingletonException): + pass
+ + + +
+[docs] +class HiFi(SerialSingleton): +
+[docs] + @validate_call + def __init__(self, *args, sampling_rate_hz: int = 192000, attenuation_db: int = 0, **kwargs) -> None: + super().__init__(*args, **kwargs) + if not self.handshake(): + raise OSError(f'Handshake with Bpod Hifi Module on {self.portstr} failed') + self.handshake() + self._info = self._get_info() + self._min_attenuation_db = -120 if self.is_hd else -103 + log.debug(f'Connected to Bpod Hifi Module {"HD" if self.is_hd else "SD"} on {self.portstr}') + + self.sampling_rate_hz = sampling_rate_hz + self.attenuation_db = attenuation_db
+ + +
+[docs] + def handshake(self) -> bool: + return self.query(bytes([243])) == bytes([244])
+ + + def _get_info(self) -> _HiFiInfo: + return _HiFiInfo(*self.query(query='I', data_specifier='<?BBBIII')) + + def _set_info_field(self, field_name: str, format_str: str, op_code: bytes, value: bool | int) -> bool: + if getattr(self._info, field_name) == value: + return True + self.write_packed(format_str, op_code, value) + if self.read() == b'\x01': + setattr(self._info, field_name, value) + else: + self._info = self._get_info() + return getattr(self._info, field_name) == value + + @property + def sampling_rate_hz(self) -> int: + return self._info.sampling_rate_hz + + @sampling_rate_hz.setter + @validate_call + def sampling_rate_hz(self, sampling_rate: int) -> None: + log.debug(f'Setting sampling rate to {sampling_rate} Hz') + if sampling_rate not in [44100, 48e3, 96e3, 192e3]: + raise ValueError('Valid values are 44100, 48000, 96000 or 192000') + if not self._set_info_field('sampling_rate_hz', '<cI', b'S', sampling_rate): + raise RuntimeError('Error setting Sampling Rate') + + @property + def attenuation_db(self) -> float: + return self._info.digital_attenuation * -0.5 + + @attenuation_db.setter + @validate_call + def attenuation_db(self, attenuation_db: float) -> None: + log.debug(f'Setting digital attenuation to {self.attenuation_db} dB') + if not (self._min_attenuation_db <= attenuation_db <= 0): + raise ValueError('Valid values are in range -120 - 0') + if not self._set_info_field('digital_attenuation', '<cB', b'A', round(attenuation_db * -2)): + raise RuntimeError('Error setting Attenuation') + + @property + def is_hd(self) -> bool: + return self._info.is_hd + + @property + def bit_depth(self) -> int: + return self._info.bit_depth + + @property + def max_samples_per_waveform(self) -> int: + return self._info.max_seconds_per_waveform * 192000 + + @property + def max_envelope_samples(self) -> int: + return self._info.max_envelope_size + +
+[docs] + def load(self, index: int, data: np.ndarray[float | int], loop_mode: bool = False, loop_duration: int = 0) -> None: + assert 1 <= data.ndim <= 2 + assert 0 <= index < self._info.max_waves + + # ensure correct orientation of data + if data.ndim == 1: + data = data.reshape(-1, 1) + if data.shape[1] >= 2 >= data.shape[0] > 0: + data = data.transpose() + + # convert from float + if data.dtype == float: + # assert -1 <= data.min() <= 0 <= data.max() <= 1 + if self._info.bit_depth == 16: + data = (data * np.iinfo(np.int16).max).astype(np.int16) + elif self._info.bit_depth == 32: + data = (data * np.iinfo(np.int32).max).astype(np.int32) + else: + raise NotImplementedError + + # get array dimensions + n_samples, n_channels = data.shape + if n_samples > self.max_samples_per_waveform: + raise RuntimeError( + f'Waveform too long - maximum supported length is {self.max_samples_per_waveform} ' + f'samples ({self.max_samples_per_waveform / self.sampling_rate_hz:.1f}s at ' + f'{self.sampling_rate_hz / 1E3:.1f}kHz)' + ) + is_stereo = n_channels == 2 + + log.debug(f'Loading {n_samples} {"stereo" if is_stereo else "mono"} samples to slot #{index}') + self.write_packed('<cB??II', b'L', index, is_stereo, loop_mode, loop_duration, n_samples) + if not self.query(data) == b'\x01': + raise RuntimeError('Error loading data')
+ + +
+[docs] + def push(self) -> bool: + log.debug('Pushing waveforms to playback buffers') + if not (success := self.query(b'*') == b'\x01'): + raise RuntimeError('Error pushing waveforms to playback buffers') + return success
+ + +
+[docs] + def play(self, index: int) -> None: + log.debug(f'Starting playback of sound #{index}') + self.write_packed('<cB', b'P', index)
+ + +
+[docs] + def stop(self, index: int | None = None): + if index is None: + log.debug('Stopping playback') + self.write(b'X') + else: + log.debug(f'Stopping playback of sound #{index}') + self.write_packed('<cB', b'x', index)
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/misc.html b/_modules/iblrig/misc.html new file mode 100644 index 000000000..820333f0e --- /dev/null +++ b/_modules/iblrig/misc.html @@ -0,0 +1,449 @@ + + + + + + iblrig.misc — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.misc

+"""
+Provides collection of functionality used throughout the iblrig repository.
+
+Assortment of functions, frequently used, but without a great deal of commonality. Functions can,
+and should, be broken out into their own files and/or classes as the organizational needs of this
+repo change over time.
+"""
+
+import argparse
+import datetime
+import logging
+from collections.abc import Sequence
+from pathlib import Path
+from typing import Literal
+
+import numpy as np
+
+FLAG_FILE_NAMES = ['transfer_me.flag', 'create_me.flag', 'poop_count.flag', 'passive_data_for_ephys.flag']
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +def get_task_argument_parser(parents: Sequence[argparse.ArgumentParser] = None): + """ + Return the task's argument parser. + + This function is kept separate from parsing for purposes of unit testing. + """ + parser = argparse.ArgumentParser(parents=parents or []) + parser.add_argument('-s', '--subject', required=True, help='Subject name') + parser.add_argument('-u', '--user', required=False, default=None, help='Alyx username to register the session') + parser.add_argument( + '-p', + '--projects', + nargs='+', + default=[], + help="project name(s), something like 'psychedelics' or 'ibl_neuropixel_brainwide_01'; if specify " + 'multiple projects, use a space to separate them', + ) + parser.add_argument( + '-c', + '--procedures', + nargs='+', + default=[], + help="long description of what is occurring, something like 'Ephys recording with acute probe(s)'; " + 'be sure to use the double quote characters to encapsulate the description and a space to separate ' + 'multiple procedures', + ) + parser.add_argument('-w', '--weight', type=float, dest='subject_weight_grams', required=False, default=None) + parser.add_argument('--no-interactive', dest='interactive', action='store_false') + parser.add_argument('--append', dest='append', action='store_true') + parser.add_argument('--stub', type=Path, help='Path to _ibl_experiment.description.yaml stub file.') + parser.add_argument( + '--log-level', + default='INFO', + help='verbosity of the console logger (default: INFO)', + choices=['NOTSET', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'CRITICAL'], + ) + parser.add_argument('--wizard', dest='wizard', action='store_true', help=argparse.SUPPRESS) + return parser
+ + + +def _post_parse_arguments(**kwargs): + """ + Post-process arguments after parsing. + + This function is used to force the interactive mode to True (as it is a call from a user) and to override the + settings file value for the user. This function is split for the purpos of unit-testing. + + Parameters + ---------- + kwargs : dict + Keyword arguments passed to argparse.ArgumentParser. + + Returns + ------- + kwargs : dict + Keyword arguments passed to argparse.ArgumentParser. + """ + # override the settings file value if the user is specified + user = kwargs.pop('user') + if user is not None: + kwargs['iblrig_settings'] = {'ALYX_USER': user} + return kwargs + + +
+[docs] +def get_task_arguments(parents: Sequence[argparse.ArgumentParser] = None): + """ + Parse input to run the tasks. All the variables are fed to the Session instance + task.py -s subject_name -p projects_name -c procedures_name --no-interactive + :param extra_args: list of dictionaries of additional argparse arguments to add to the parser + For example, to add a new toto and titi arguments, use: + get_task_arguments({'--toto', type=str, default='toto'}, {'--titi', action='store_true', default=False}) + :return: + """ + parser = get_task_argument_parser(parents=parents) + kwargs = vars(parser.parse_args()) + return _post_parse_arguments(**kwargs)
+ + + +def _is_datetime(x: str) -> bool: + """ + Check if a string is a date in the format YYYY-MM-DD. + + Parameters + ---------- + x : str + The string to check. + + Returns + ------- + bool or None + True if the string matches the date format, False otherwise, or None if there's an exception. + """ + try: + datetime.strptime(x, '%Y-%m-%d') + return True + except ValueError: + return False + + +
+[docs] +def get_session_path(path: str | Path) -> Path | None: + """Returns the session path from any filepath if the date/number pattern is found.""" + if path is None: + return + if isinstance(path, str): + path = Path(path) + sess = None + for i, p in enumerate(path.parts): + if p.isdigit() and _is_datetime(path.parts[i - 1]): + sess = Path().joinpath(*path.parts[: i + 1]) + + return sess
+ + + +
+[docs] +def get_port_events(events: dict, name: str = '') -> list: + out: list = [] + for k in events: + if name in k: + out.extend(events[k]) + out = sorted(out) + + return out
+ + + +
+[docs] +def truncated_exponential(scale: float = 0.35, min_value: float = 0.2, max_value: float = 0.5) -> float: + """ + Generate a truncated exponential random variable within a specified range. + + Parameters + ---------- + scale : float, optional + Scale of the exponential distribution (inverse of rate parameter). Defaults to 0.35. + min_value : float, optional + Minimum value for the truncated range. Defaults to 0.2. + max_value : float, optional + Maximum value for the truncated range. Defaults to 0.5. + + Returns + ------- + float + Truncated exponential random variable. + + Notes + ----- + This function generates a random variable from an exponential distribution + with the specified `scale`. It then checks if the generated value is within + the specified range `[min_value, max_value]`. If it is within the range, it returns + the generated value; otherwise, it recursively generates a new value until it falls + within the specified range. + + The `scale` should typically be greater than or equal to the `min_value` to avoid + potential issues with infinite recursion. + """ + x = np.random.exponential(scale) + if min_value <= x <= max_value: + return x + else: + return truncated_exponential(scale, min_value, max_value)
+ + + +
+[docs] +def get_biased_probs(n: int, idx: int = -1, p_idx: float = 0.5) -> list[float]: + """ + Calculate biased probabilities for all elements of an array such that the + `i`th value has probability `p_i` for being drawn relative to the remaining + values. + + See: https://github.com/int-brain-lab/iblrig/issues/74 + + Parameters + ---------- + n : int + The length of the array, i.e., the number of probabilities to generate. + idx : int, optional + The index of the value that has the biased probability. Defaults to -1. + p_idx : float, optional + The probability of the `idx`-th value relative to the rest. Defaults to 0.5. + + Returns + ------- + List[float] + List of biased probabilities. + + Raises + ------ + IndexError + If `idx` is out of range + ValueError + If `p_idx` is 0. + """ + if n == 1: + return [1.0] + if idx not in range(-n, n): + raise IndexError('`idx` is out of range.') + if p_idx == 0: + raise ValueError('Probability must be larger than 0.') + z = n - 1 + p_idx + p = [1 / z] * n + p[idx] *= p_idx + return p
+ + + +
+[docs] +def draw_contrast( + contrast_set: list[float], + probability_type: Literal['skew_zero', 'biased', 'uniform'] = 'biased', + idx: int = -1, + idx_probability: float = 0.5, +) -> float: + """ + Draw a contrast value from a given iterable based to the specified probability type. + + Parameters + ---------- + contrast_set : list[float] + The set of contrast values from which to draw. + probability_type : Literal["skew_zero", "biased", "uniform"], optional + The type of probability distribution to use. + - "skew_zero" or "biased": Draws with a biased probability distribution based on idx and idx_probability, + - "uniform": Draws with a uniform probability distribution. + Defaults to "biased". + idx : int, optional + Index for probability manipulation (with "skew_zero" or "biased"), default: -1. + idx_probability : float, optional + Probability for the specified index (with "skew_zero" or "biased"), default: 0.5. + + Returns + ------- + float + The drawn contrast value. + + Raises + ------ + ValueError + If an unsupported `probability_type` is provided. + """ + if probability_type in ['skew_zero', 'biased']: + p = get_biased_probs(n=len(contrast_set), idx=idx, p_idx=idx_probability) + return np.random.choice(contrast_set, p=p) + elif probability_type == 'uniform': + return np.random.choice(contrast_set) + else: + raise ValueError("Unsupported probability_type. Use 'skew_zero', 'biased', or 'uniform'.")
+ + + +
+[docs] +def online_std(new_sample: float, new_count: int, old_mean: float, old_std: float) -> tuple[float, float]: + """ + Update the mean and standard deviation of a group of values after a sample update. + + Parameters + ---------- + new_sample : float + The new sample to be included. + new_count : int + The new count of samples (including new_sample). + old_mean : float + The previous mean (N - 1). + old_std : float + The previous standard deviation (N - 1). + + Returns + ------- + tuple[float, float] + Updated mean and standard deviation. + """ + if new_count == 1: + return new_sample, 0.0 + new_mean = (old_mean * (new_count - 1) + new_sample) / new_count + new_std = np.sqrt((old_std**2 * (new_count - 1) + (new_sample - old_mean) * (new_sample - new_mean)) / new_count) + return new_mean, new_std
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/net.html b/_modules/iblrig/net.html new file mode 100644 index 000000000..7c811eb22 --- /dev/null +++ b/_modules/iblrig/net.html @@ -0,0 +1,727 @@ + + + + + + iblrig.net — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.net

+"""
+Network communication between rigs.
+
+An example of a remote_rigs.yaml file:
+
+```yaml
+neuropixel: '12.134.270.1'
+'cameras:left': 'tcp://0.123.456.7:9998'
+'cameras:right': 'tcp://0.123.456.6:9998'
+tasks: 'udp://123.654.8.8'
+```
+
+Todo
+----
+TODO case study: starts services but times out due to one service.
+ How to restart without stopping services? Perhaps it can throw a
+ warning if the status is running but continue on anyway?
+TODO perhaps confirmed_send should ensure that data is list with
+ element 1 being an exp message
+TODO Rewrite video session function with loop
+TODO Implement video end and cleanups
+TODO tests for clear_callbacks cancel future
+TODO test error_received and connection_lost
+TODO Services init alyx callback
+TODO await all timeout tests
+TODO test individual CammeraSession methods
+TODO Test for keyboard input
+TODO Process keyboard input
+TODO Document read stdin
+TODO Finish prep ephys session
+
+Examples
+--------
+Send a standard message (e.g. start) to all rigs and await their responses:
+
+>>> responses = await services.start(exp_ref)
+
+Send a standard message to all rigs without awaiting responses:
+
+>>> for service in services.values():
+...     await service.init()
+
+Send exp info message to all rigs and await their responses:
+
+>>> responses = await self.services._signal(ExpMessage.EXPINFO, 'confirmed_send', [ExpMessage.EXPINFO, ...])
+
+Send exp info message to all rigs without awaiting responses:
+
+>>> for service in services.values():
+...     await service.confirmed_send([ExpMessage.EXPINFO, ...])
+
+Request status from a single service (await echo):
+
+>>> await services['cameras'].confirmed_send([ExpMessage.EXPSTATUS])
+
+Send message to a single service without awaiting echo:
+NB: use with causion: can cause infinite loops if both not correctly configured
+
+>>> services['cameras'].send([ExpMessage.EXPSTATUS])
+
+"""
+
+import asyncio
+import logging
+import sys
+import threading
+import time
+from dataclasses import dataclass, field
+from urllib.parse import urlparse
+
+import yaml
+
+import one.params
+from iblrig import __version__
+from iblrig.path_helper import get_local_and_remote_paths
+from iblutil.io import net
+from iblutil.io.params import FileLock
+from one.api import OneAlyx
+from one.webclient import AlyxClient
+
+log = logging.getLogger(__name__)
+log.setLevel(10)
+
+
+
+[docs] +class Auxiliaries: + services = None + """iblutil.io.net.app.Services: A map of remote services.""" + refresh_rate = 0.2 + """float: How long to wait between checking message queue.""" + _clients = {} + """dict: Map of remote service names and their corresponding URI.""" + _queued: dict[float, list] = {} + """dict: The messages queued for delivery by async thread.""" + _awaiting: dict[threading.Event] + _log: dict[float, dict] = {} + """dict: Map of request times and the remote responses.""" + stop_event = None + """threading.Event: A thread event. Once set, thread stops listening and clean up services.""" + response_received = None + """threading.Event: A thread event. Notified each time the async thread receives all responses.""" + connected = None + """threading.Event: A thread event. Set by async thread once all services connected.""" + _thread = None + """threading.Thread: An async thread handle.""" + +
+[docs] + def __new__(cls, *args, **kwargs): + cls.response_received = threading.Condition() + cls.connected = threading.Condition() + cls.stop_event = threading.Event() + return super().__new__(cls)
+ + +
+[docs] + def __init__(self, clients): + """ + Connect to and communicate with one or more remote rigs synchronously. + + Parameters + ---------- + clients : dict[str, str] + A map of name to URI. + """ + # Load clients + self._clients = clients or {} + if any(self._clients): + self._thread = threading.Thread(target=asyncio.run, args=(self.listen(),), name='network_coms') + self._thread.start()
+ + + @property + def is_connected(self) -> bool: + """bool: True if successfully connected to services.""" + return any(self.services or []) and self.services.is_connected + + @property + def is_running(self) -> bool: + """bool: True if listen is running on another thread.""" + return self.stop_event and not self.stop_event.is_set() + +
+[docs] + def clear_message_queue(self): + """ + Clear queued messages. + + Returns + ------- + int + The number of aborted messages. + """ + n_aborted = len(self._queued) + self._queued.clear() + if n_aborted: + log.debug('%i remote service messages aborted', n_aborted) + return n_aborted
+ + +
+[docs] + async def cleanup(self, notify_services=False): + """ + Close connections and cleanup services. + + This method closes all service communicators and cancels any pending callbacks. + + Parameters + ---------- + notify_services : bool + If true, send EXPCLEANUP message to remote devices before cleanup. + """ + self._queued.clear() + if notify_services: # Send cleanup message to services without await response + await self.services._signal(net.base.ExpMessage.EXPCLEANUP, 'cleanup', reverse=True, concurrent=True) + self.services.close()
+ + +
+[docs] + def close(self): + """Close communicators and wait for thread to terminate.""" + self.clear_message_queue() + if self._thread: + self.stop_event.set() + self._thread.join(timeout=5) # wait for thread to exit
+ + +
+[docs] + async def create(self): + """ + Create remote services object. + + Instantiates communicator objects which establish the UDP connections, wraps them in the + Service class for bulk messaging, sets connected property to True and assigns some logging + callbacks. This should be called from a daemon thread. + """ + with self.connected: + remote_rigs = [await net.app.EchoProtocol.client(uri, name) for name, uri in self._clients.items()] + self.services = net.app.Services(remote_rigs, timeout=10) + self.connected.notify() + log.debug('Connected...') + # Assign a callback to all clients + self.services.assign_callback('EXPSTART', lambda _, addr: print('{}:{} started'.format(*addr)))
+ + +
+[docs] + async def listen(self): + """ + Listen for messages in queue and push to remote services. + + Creates service communicators then awaits messages added to the queue. Once added, these + are sent to the remote services and the collated responses are added to the log. + Exits only after stop event is set. This should be called from a daemon thread. + """ + await self.create() + while not self.stop_event.is_set(): + if any(queue := sorted(self._queued)): + request_time = queue[0] + t_str = time.strftime('%H:%M:%S', time.localtime(request_time)) + event, args, kwargs = self._queued[request_time] + if not isinstance(event, net.base.ExpMessage): + raise TypeError('invalid message cued at ' + t_str) + log.debug('Sending %s message requested at %s', event.name, t_str) + try: + match event: + case net.base.ExpMessage.EXPSTART: + responses = await self.services.start(*args) + case net.base.ExpMessage.EXPINIT: + responses = await self.services.init(*args) + case net.base.ExpMessage.EXPEND | net.base.ExpMessage.EXPINTERRUPT: + responses = await self.services.stop(args, immediately=event is net.base.ExpMessage.EXPINTERRUPT) + case net.base.ExpMessage.EXPINFO: + # TODO Instead of waiting for all responses, cancel futures when main sync responds? + # async def first(aiterable, condition=lambda i: True): + # for x in aiterable: + # x = await x + # if condition(x): + # yield x + # + # res = await anext(first(asyncio.as_completed(tasks), lambda r: r[-1]['main_sync'])) + responses = await self.services.info(event, *args) + case net.base.ExpMessage.ALYX: + responses = await self.services.alyx(*args) + case _: + responses = NotImplementedError(event) + except asyncio.TimeoutError as ex: # TODO broaden exception + log.error('Timeout error: %s', ex) + responses = ex + with self.response_received: + self._log[request_time] = responses + if request_time in self._queued: # may have been removed if `close` called + del self._queued[request_time] # remove from queue + self.response_received.notify() + if not self.stop_event.is_set(): + await asyncio.sleep(self.refresh_rate) + await self.cleanup()
+ + +
+[docs] + def push(self, message: net.base.ExpMessage, *args, wait=False, **kwargs): + """Queue message for dispatch to remote services. + + This method synchronously logs the request time and pushes the message to the queue for the + asynchronous thread to handle. + + Parameters + ---------- + message : iblutil.io.net.base.ExpMessage + An experiment message to send to remote services. + args : any + One or more optional variables to send. + wait : bool + If True, this method is blocking and once all messages are received (or timed out) the + collated responses are returned. Otherwise the request timestamp is returned for use as + a log key when fetching the responses in a non-blocking manner. + kwargs + Optional keyword arguments to use in calling communicator methods (currently unused). + + Returns + ------- + Exception | dict | float + An exception if failed to receive all responses in time, otherwise a map of service + name and response if wait is true, or the request time if wait is false. + + Raises + ------ + RuntimeError + The async thread failed to return a response, most likely due to an error in the listen + method. + """ + request_time = time.time() + message = net.base.ExpMessage.validate(message, allow_bitwise=False) + assert request_time not in self._queued, 'too many requests sent at once' + assert self.is_running + # The expected max time for the thread to return control + thread_timeout = self.services.timeout + self.refresh_rate + with self.response_received: # lock thread so it can't process the message before we can wait on it (very unlikely) + self._queued[request_time] = [message, args, kwargs] + if not wait: + return request_time + success = self.response_received.wait_for(lambda: request_time in self._log, timeout=thread_timeout) + if not success: + # probably a timeout or other failure + raise RuntimeError('Thread failed to return') + return self._log[request_time]
+
+ + + +
+[docs] +def install_alyx_token(base_url, token): + """Save Alyx token sent from remote device. + + Saves an Alyx token into the ONE params for a given database instance. + + Parameters + ---------- + base_url : str + The Alyx database URL. + token : dict[str, dict] + The token in the form {username: {'token': token}}. + + Returns + ------- + bool + True if the token was far a user not already cached. + """ + par = one.params.get(base_url, silent=True).as_dict() + is_new_user = next(iter(token), None) not in par.get('TOKEN', {}) + par.setdefault('TOKEN', {}).update(token) + one.params.save(par, base_url) + return is_new_user
+ + + +
+[docs] +def update_alyx_token(data, _, alyx=None, one=None): + """Callback to update instance with Alyx token. + + Parameters + ---------- + data : (str, dict) + Tuple containing the Alyx database URL and token dict. + addr : (str, int) + The address of the remote host that sent the Alyx data (unused). + alyx : one.webclient.AlyxClient + An optional instance of Alyx to update with the token. + one.api.OneAlyx + An optional instance of ONE to update with the token. + + Returns + ------- + bool + If True, the provided alyx or one instance was successfully updated with the token. + """ + base_url, token = data + if not (base_url and token) or not (alyx or one): + return False + if one and not isinstance(one, OneAlyx): + return False + username = next(iter(token)) + if not alyx: + alyx = one._web_client or AlyxClient(base_url=base_url, username=username, silent=True) + # Update alyx object + alyx._par = ( + alyx._par.set('ALYX_URL', base_url) + .set('ALYX_LOGIN', username) + .set('TOKEN', {**alyx._par.as_dict().get('TOKEN', {}), **token}) + ) + alyx._token = alyx._par.TOKEN[username] + alyx._headers = {'Authorization': f'Token {list(alyx._token.values())[0]}', 'Accept': 'application/json'} + alyx.user = username + alyx.base_url = base_url + alyx.silent = True # ensure Alyx doesn't attempt to prompt user for input + # Update ONE object + if one: + one._web_client = alyx + one.mode = 'remote' if alyx.is_logged_in else 'local' + return alyx.is_logged_in
+ + + +
+[docs] +@dataclass +class ExpInfo: + """A standard experiment information structure.""" + + exp_ref: str + main_sync: bool + experiment_description: dict = field(default_factory=dict) + master: bool = False + rig_version: str = __version__ + spec_version: str = net.base.ExpMessage.__version__ + +
+[docs] + def to_dict(self): + return self.__dict__
+
+ + + +
+[docs] +def get_remote_devices_file(iblrig_settings=None): + """ + Return the location of the remote devices YAML file. + + Parameters + ---------- + iblrig_settings : dict + A settings dictionary, otherwise will load the default settings from file. + + Returns + ------- + pathlib.Path, None + The full path to the remote devices YAML file in the remote data folder, or None if the folder is not defined. + """ + if remote_data_folder := get_local_and_remote_paths(iblrig_settings=iblrig_settings)['remote_data_folder']: + return remote_data_folder.joinpath('remote_devices.yaml')
+ + + +
+[docs] +def get_remote_devices(remote_devices_file=None, iblrig_settings=None): + """ + Return map of device name to network URI. + + Parameters + ---------- + remote_devices_file : pathlib.Path + Optional remote data path. + iblrig_settings : dict + A settings dictionary, otherwise will load the default settings from file. Used to + determine the remote data path (the remote_data_folder param). + + Returns + ------- + dict[str, str] + A map of device name to network URI, e.g. {'cameras': 'udp://127.0.0.1:11001'}. + """ + remote_devices = {} + if not remote_devices_file: + remote_devices_file = get_remote_devices_file(iblrig_settings=iblrig_settings) + elif remote_devices_file.is_dir(): + remote_devices_file /= 'remote_devices.yaml' + if remote_devices_file and remote_devices_file.exists(): + with open(remote_devices_file) as f: + remote_devices = yaml.safe_load(f) + return remote_devices
+ + + +
+[docs] +async def get_server_communicator(service_uri, name: str): + """ + + Parameters + ---------- + service_uri : bool, None, str + name : str + + Returns + ------- + iblutil.io.net.app.EchoProtocol, None + A Communicator instance, or None if server_uri is False. + bool + True if the URI matches the one in the file, False otherwise. + """ + if service_uri is False: + return None, False + if service_uri in (None, True, ''): + lan_ip = net.base.hostname2ip() # Local area network IP of this PC + service_uri = net.base.validate_uri(lan_ip) # Listen for server message on this local port + return await check_uri_match(await net.app.EchoProtocol.server(service_uri, name=name))
+ + + +
+[docs] +async def check_uri_match(com: net.app.EchoProtocol, update=None) -> (net.app.EchoProtocol, bool): + """ + Log warning if URI in remote devices is wrong. + + NB: Currently does not check if the protocol matches, and does not resolve hostnames. + + Parameters + ---------- + com : iblutil.io.net.app.EchoProtocol + A Communicator instance to compare to the devices file. + update : bool, None + If True, update the remote devices YAML file. If False, do not update the remote devices YAML file. If None, + only updates if the file exists. + + Returns + ------- + iblutil.io.net.app.EchoProtocol + The same Communicator instance. + bool + True if the URI matches the one in the file, False otherwise. When update is True, True should always be + returned. + + Raises + ------ + FileNotFoundError + Raised when update is True but the remote devices YAML file does not exist on disk. + """ + match = False + remote_devices = get_remote_devices() or {} + if expected := remote_devices.get(com.name): + expected = net.base.validate_uri(expected) + ip, _, port = urlparse(expected).netloc.rpartition(':') + match = (ip, int(port)) == (com.hostname, com.port) + if not match: + log.warning( + 'remote devices specifies %s as %s:%s, communicator listening on %s:%s.', com.name, ip, port, com.hostname, port + ) + + if update is not False and not match: + remote_devices_file = get_remote_devices_file() + if update is True and not remote_devices_file.exists(): + raise FileNotFoundError('Remote data folder not defined.') + if remote_devices_file: + remote_devices_file.parent.mkdir(exist_ok=True, parents=True) + async with FileLock(remote_devices_file, timeout=10, log=log): + with remote_devices_file.open('w') as fp: + remote_devices.update({com.name: com.server_uri}) + yaml.safe_dump(remote_devices, fp) + match = True + return com, match
+ + + +
+[docs] +async def read_stdin(loop=None): + """ + Asynchronously reads lines from standard input. + + Allows asynchronous reading of user keyboard input. Currently there is no cross-platform way to listen to + keypresses, but this function comes close. + + Parameters + ---------- + loop : asyncio.AbstractEventLoop + An optional event loop to use. + + Yields + ------ + str + A line of text from the standard input, if available. + """ + loop = loop or asyncio.get_event_loop() + while sys.stdin.readable(): + if line := await loop.run_in_executor(None, sys.stdin.readline): + yield line
+ + + +if __name__ == '__main__': + lan_ip = net.base.hostname2ip() + remote_rigs = Auxiliaries({'cameras': str(lan_ip) + ':99998', 'timeline': '192.168.1.236:99998'}) + alyx = AlyxClient() + alyx.authenticate('miles') + assert alyx.is_logged_in + r = remote_rigs.push('ALYX', alyx, wait=True) + r = remote_rigs.push('EXPINFO', dict(subject='subject'), wait=True) + # assert sum(x[-1]['main_sync'] for x in r.values()), 'one main sync expected' + # + # + # while remote_rigs.started is False: + # time.sleep(1) + # assert remote_rigs.started is True + + # Thread(target = func2).start() + # send a token + """ + [net.base.ExpMessage.ALYX, alyx.base_url, {alyx.user: alyx._token}] + """ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/online_plots.html b/_modules/iblrig/online_plots.html new file mode 100644 index 000000000..a52f2a4a9 --- /dev/null +++ b/_modules/iblrig/online_plots.html @@ -0,0 +1,579 @@ + + + + + + iblrig.online_plots — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.online_plots

+import datetime
+import json
+import logging
+import time
+from pathlib import Path
+
+import matplotlib.pyplot as plt
+import numpy as np
+import pandas as pd
+import seaborn as sns
+from pandas.api.types import CategoricalDtype
+
+import one.alf.io
+from iblrig.choiceworld import get_subject_training_info
+from iblrig.misc import online_std
+from iblrig.raw_data_loaders import load_task_jsonable
+from iblutil.util import Bunch
+
+NTRIALS_INIT = 2000
+NTRIALS_PLOT = 20  # do not edit - this is used also to enforce the completion criteria
+CONTRAST_SET = np.array([0, 1 / 16, 1 / 8, 1 / 4, 1 / 2, 1])  # used as a default if instantiated without settings
+PROBABILITY_SET = np.array([0.2, 0.5, 0.8])  # used as a default if instantiated without settings
+# if the mouse does less than 400 trials in the first 45mins it's disengaged
+ENGAGED_CRITIERION = {'secs': 45 * 60, 'trial_count': 400}
+
+log = logging.getLogger(__name__)
+sns.set_style('darkgrid')
+
+
+
+[docs] +class DataModel: + """ + The data model is a pure numpy / pandas container for the choice world task. + It contains: + - a psychometrics dataframe that contains the count / choice and response time + per signed contrast and block contingency + - a last trials dataframe that contains 20 trials worth of data for the timeline view + - various counters such as ntrials and water delivered + """ + + task_settings = None + probability_set = PROBABILITY_SET + contrast_set = CONTRAST_SET + ntrials = 0 + ntrials_correct = 0 + ntrials_nan = np.nan + ntrials_engaged = 0 # trials happening within the first 400s + percent_correct = np.nan + percent_error = np.nan + water_delivered = 0.0 + time_elapsed = 0.0 + +
+[docs] + def __init__(self, settings_file: Path | None): + self.session_path = one.alf.files.get_session_path(settings_file) or '' + self.last_trials = pd.DataFrame( + columns=['correct', 'signed_contrast', 'stim_on', 'play_tone', 'reward_time', 'error_time', 'response_time'], + index=np.arange(NTRIALS_PLOT), + ) + if settings_file is not None and settings_file.exists(): + # most of the IBL tasks have a predefined set of probabilities (0.2, 0.5, 0.8), but in the + # case of the advanced choice world task, the probabilities are defined in the task settings + with open(settings_file) as fid: + self.task_settings = json.load(fid) + self.probability_set = [self.task_settings['PROBABILITY_LEFT']] + self.task_settings.get('BLOCK_PROBABILITY_SET', []) + self.contrast_set = self.task_settings.get('CONTRAST_SET', CONTRAST_SET) + log.info(f'Settings from file: contrast set {self.contrast_set}, probability set {self.probability_set}') + else: + log.warning( + f'Settings file not found - using default probabilities {self.probability_set} and contrasts {CONTRAST_SET}' + ) + + # instantiate the psychometrics dataframe + signed_contrasts = np.r_[-np.flipud(np.unique(np.abs(self.contrast_set))[1:]), np.unique(np.abs(self.contrast_set))] + self.psychometrics = pd.DataFrame( + columns=['count', 'response_time', 'choice', 'response_time_std', 'choice_std'], + index=pd.MultiIndex.from_product([self.probability_set, signed_contrasts]), + ) + self.psychometrics['count'] = 0 + self.trials_table = pd.DataFrame(columns=['response_time'], index=np.arange(NTRIALS_INIT)) + + # for the trials plots this is the background image showing green if correct, red if incorrect + self.rgb_background = np.ones((NTRIALS_PLOT, 1, 3), dtype=np.uint8) * 229 + self.rgb_background[self.last_trials.correct == False, 0, 0] = 255 # noqa + self.rgb_background[self.last_trials.correct == True, 0, 1] = 255 # noqa + # keep the last contrasts as a 20 by 2 array + ileft = np.where(self.last_trials.signed_contrast < 0)[0] # negative position is left + iright = np.where(self.last_trials.signed_contrast > 0)[0] + self.last_contrasts = np.zeros((NTRIALS_PLOT, 2)) + self.last_contrasts[ileft, 0] = np.abs(self.last_trials.signed_contrast[ileft]) + self.last_contrasts[iright, 1] = np.abs(self.last_trials.signed_contrast[iright])
+ + +
+[docs] + def update_trial(self, trial_data, bpod_data) -> None: + # update counters + self.time_elapsed = bpod_data['Trial end timestamp'] - bpod_data['Bpod start timestamp'] + if self.time_elapsed <= (ENGAGED_CRITIERION['secs']): + self.ntrials_engaged += 1 + self.ntrials += 1 + self.water_delivered += trial_data.reward_amount + self.ntrials_correct += trial_data.trial_correct + signed_contrast = np.sign(trial_data['position']) * trial_data['contrast'] + choice = trial_data.position > 0 if trial_data.trial_correct else trial_data.position < 0 + self.trials_table.at[self.ntrials, 'response_time'] = trial_data.response_time + + # update psychometrics using online statistics method + indexer = (trial_data.stim_probability_left, signed_contrast) + if indexer not in self.psychometrics.index: + self.psychometrics.loc[indexer, :] = np.NaN + self.psychometrics.loc[indexer, ('count')] = 0 + self.psychometrics.loc[indexer, ('count')] += 1 + self.psychometrics.loc[indexer, ('response_time')], self.psychometrics.loc[indexer, ('response_time_std')] = online_std( + new_sample=trial_data.response_time, + new_count=self.psychometrics.loc[indexer, ('count')], + old_mean=self.psychometrics.loc[indexer, ('response_time')], + old_std=self.psychometrics.loc[indexer, ('response_time_std')], + ) + self.psychometrics.loc[indexer, ('choice')], self.psychometrics.loc[indexer, ('choice_std')] = online_std( + new_sample=float(choice), + new_count=self.psychometrics.loc[indexer, ('count')], + old_mean=self.psychometrics.loc[indexer, ('choice')], + old_std=self.psychometrics.loc[indexer, ('choice_std')], + ) + # update last trials table + self.last_trials = self.last_trials.shift(-1) + i = NTRIALS_PLOT - 1 + self.last_trials.at[i, 'correct'] = trial_data.trial_correct + self.last_trials.at[i, 'signed_contrast'] = signed_contrast + self.last_trials.at[i, 'stim_on'] = bpod_data['States timestamps'].get('stim_on', [[np.nan]])[0][0] + self.last_trials.at[i, 'play_tone'] = bpod_data['States timestamps'].get('play_tone', [[np.nan]])[0][0] + self.last_trials.at[i, 'reward_time'] = bpod_data['States timestamps'].get('reward', [[np.nan]])[0][0] + self.last_trials.at[i, 'error_time'] = bpod_data['States timestamps'].get('error', [[np.nan]])[0][0] + self.last_trials.at[i, 'response_time'] = trial_data.response_time + # update rgb image + self.rgb_background = np.roll(self.rgb_background, -1, axis=0) + self.rgb_background[-1] = np.array([0, 255, 0]) if trial_data.trial_correct else np.array([255, 0, 0]) + # update contrasts + self.last_contrasts = np.roll(self.last_contrasts, -1, axis=0) + self.last_contrasts[-1, :] = 0 + self.last_contrasts[-1, int(self.last_trials.signed_contrast.iloc[-1] > 0)] = abs( + self.last_trials.signed_contrast.iloc[-1] + ) + self.ntrials_nan = self.ntrials if self.ntrials > 0 else np.nan + self.percent_correct = self.ntrials_correct / self.ntrials_nan * 100
+ + +
+[docs] + def compute_end_session_criteria(self): + """Implement critera to change the color of the figure display, according to the specifications of the task.""" + colour = {'red': '#eb5757', 'green': '#57eb8b', 'yellow': '#ede34e', 'white': '#ffffff'} + # Within the first part of the session we don't apply response time criterion + if self.time_elapsed < ENGAGED_CRITIERION['secs']: + return colour['white'] + # if the mouse has been training for more than 90 minutes subject training too long + elif self.time_elapsed > (90 * 60): + return colour['red'] + # the mouse fails to do more than 400 trials in the first 45 mins + elif self.ntrials_engaged <= ENGAGED_CRITIERION['trial_count']: + return colour['green'] + # the subject reaction time over the last 20 trials is more than 5 times greater than the overall reaction time + elif (self.trials_table['response_time'][: self.ntrials].median() * 5) < self.last_trials['response_time'].median(): + return colour['yellow'] + # 90 > time > 45 min and subject's avg response time hasn't significantly decreased + else: + return colour['white']
+
+ + + +
+[docs] +class OnlinePlots: + """ + Full object to implement the online plots + Either the object is instantiated in a static mode from an existing jsonable file and it will produce the figure + >>> oplt = OnlinePlots(settings) + Or it can be instantiated empty, and then run on a file during acquisition. + Use ctrl + Z to interrupt + >>> OnlinePlots().run(jsonable_file) + """ + +
+[docs] + def __init__(self, settings_file=None): + settings_file = Path(settings_file) if settings_file is not None else None + self.data = DataModel(settings_file=settings_file) + + # create figure and axes + h = Bunch({}) + h.fig = plt.figure(constrained_layout=True, figsize=(10, 8)) + self._set_session_string() + h.fig_title = h.fig.suptitle(f'{self._session_string}') + nc = 9 + hc = nc // 2 + h.gs = h.fig.add_gridspec(2, nc) + h.ax_trials = h.fig.add_subplot(h.gs[:, :hc]) + h.ax_psych = h.fig.add_subplot(h.gs[0, hc : nc - 1]) + h.ax_performance = h.fig.add_subplot(h.gs[0, nc - 1]) + h.ax_reaction = h.fig.add_subplot(h.gs[1, hc : nc - 1]) + h.ax_water = h.fig.add_subplot(h.gs[1, nc - 1]) + + h.ax_psych.set(title='psychometric curve', xlim=[-1, 1], ylim=[0, 1]) + h.ax_reaction.set(title='reaction times', xlim=[-1, 1], ylim=[0.1, 100], yscale='log', xlabel='signed contrast') + xticks = np.arange(-1, 1.1, 0.25) + xticklabels = np.array([f'{x:g}' for x in xticks]) + xticklabels[1::2] = '' + h.ax_psych.set_xticks(xticks, xticklabels) + h.ax_reaction.set_xticks(xticks, xticklabels) + + h.ax_trials.set(yticks=[], title='trials timeline', xlim=[-5, 30], xlabel='time (s)') + h.ax_trials.set_xticks(h.ax_trials.get_xticks(), [''] + h.ax_trials.get_xticklabels()[1::]) + h.ax_performance.set(xticks=[], xlim=[-0.6, 0.6], ylim=[0, 100], title='performance') + h.ax_water.set(xticks=[], xlim=[-0.6, 0.6], ylim=[0, 1000], title='reward') + + # create psych curves + h.curve_psych = {} + h.curve_reaction = {} + for p in self.data.probability_set: + h.curve_psych[p] = h.ax_psych.plot( + self.data.psychometrics.loc[p].index, + self.data.psychometrics.loc[p]['choice'], + '.-', + zorder=10, + clip_on=False, + label=f'p = {p}', + ) + h.curve_reaction[p] = h.ax_reaction.plot( + self.data.psychometrics.loc[p].index, self.data.psychometrics.loc[p]['response_time'], '.-', label=f'p = {p}' + ) + h.ax_psych.legend() + h.ax_reaction.legend() + + # create the two bars on the right side + h.bar_correct = h.ax_performance.bar(0, self.data.percent_correct, label='correct', color='k') + h.bar_water = h.ax_water.bar(0, self.data.water_delivered, label='water delivered', color='b') + + # create the trials timeline view in a single axis + xpos = np.tile([[-3.75, -1.25]], (NTRIALS_PLOT, 1)).T.flatten() + ypos = np.tile(np.arange(NTRIALS_PLOT), 2) + h.im_trials = h.ax_trials.imshow( + self.data.rgb_background, alpha=0.2, extent=[-10, 50, -0.5, NTRIALS_PLOT - 0.5], aspect='auto', origin='lower' + ) + kwargs = dict(markersize=10, markeredgewidth=2) + h.lines_trials = { + 'stim_on': h.ax_trials.plot( + self.data.last_trials.stim_on, np.arange(NTRIALS_PLOT), '|', color='b', **kwargs, label='stimulus on' + ), + 'reward_time': h.ax_trials.plot( + self.data.last_trials.reward_time, np.arange(NTRIALS_PLOT), '|', color='g', **kwargs, label='reward' + ), + 'error_time': h.ax_trials.plot( + self.data.last_trials.error_time, np.arange(NTRIALS_PLOT), '|', color='r', **kwargs, label='error' + ), + 'play_tone': h.ax_trials.plot( + self.data.last_trials.play_tone, np.arange(NTRIALS_PLOT), '|', color='m', **kwargs, label='tone' + ), + } + h.scatter_contrast = h.ax_trials.scatter( + xpos, ypos, s=250, c=self.data.last_contrasts.T.flatten(), alpha=1, marker='o', vmin=0.0, vmax=1, cmap='Greys' + ) + h.ax_trials.legend() + + xticks = np.arange(-1, 1.1, 0.25) + xticklabels = np.array([f'{x:g}' for x in xticks]) + xticklabels[1::2] = '' + h.ax_psych.set_xticks(xticks, xticklabels) + + self.h = h + self.update_titles() + if plt.rcParams['backend'] != 'agg': + plt.show(block=False) + plt.draw()
+ + +
+[docs] + def update_titles(self): + protocol = (self.data.task_settings['PYBPOD_PROTOCOL'] if self.data.task_settings else '').replace('_', r'\_') + spacer = r'\ \ ·\ \ ' + main_title = ( + r'$\mathbf{' + protocol + rf'{spacer}{self.data.ntrials}\ trials{spacer}time\ elapsed:\ ' + rf'{str(datetime.timedelta(seconds=int(self.data.time_elapsed)))}' + r'}$' + ) + self.h.fig_title.set_text(main_title + '\n' + self._session_string) + self.h.ax_water.title.set_text(f'total reward\n{self.data.water_delivered:.1f}μL') + self.h.ax_performance.title.set_text(f'performance\n{self.data.percent_correct:.0f}%')
+ + +
+[docs] + def update_trial(self, trial_data, bpod_data): + """ + Update, both, the data model and the graphics for an upcoming trial. + + Parameters + ---------- + trial_data : pandas.DataFrame + pandas record + bpod_data : dict + doct interpreted from the bpod json dump + :return: + """ + self.data.update_trial(trial_data, bpod_data) + self.update_graphics(pupdate=trial_data.stim_probability_left)
+ + +
+[docs] + def update_graphics(self, pupdate: float | None = None): + background_color = self.data.compute_end_session_criteria() + h = self.h + h.fig.set_facecolor(background_color) + self.update_titles() + for p in self.data.probability_set: + if pupdate is not None and p != pupdate: + continue + if self.data.psychometrics.loc[p]['count'].sum() == 0: + continue + # update psychometric curves + iok = ~np.isnan(self.data.psychometrics.loc[p]['choice'].values.astype(np.float32)) + xval = self.data.psychometrics.loc[p].index[iok] + h.curve_psych[p][0].set(xdata=xval, ydata=self.data.psychometrics.loc[p]['choice'][iok]) + h.curve_reaction[p][0].set(xdata=xval, ydata=self.data.psychometrics.loc[p]['response_time'][iok]) + # update the last trials plot + self.h.im_trials.set_array(self.data.rgb_background) + for k in ['stim_on', 'reward_time', 'error_time', 'play_tone']: + h.lines_trials[k][0].set(xdata=self.data.last_trials[k]) + self.h.scatter_contrast.set_array(self.data.last_contrasts.T.flatten()) + # update barplots + self.h.bar_correct[0].set(height=self.data.percent_correct) + self.h.bar_water[0].set(height=self.data.water_delivered)
+ + + def _set_session_string(self) -> None: + self._session_string = '' + try: + if isinstance(self.data.task_settings, dict): + training_info, _ = get_subject_training_info( + subject_name=self.data.task_settings['SUBJECT_NAME'], + task_name=self.data.task_settings['PYBPOD_PROTOCOL'], + lab=self.data.task_settings['ALYX_LAB'], + ) + self._session_string = ( + f'subject: {self.data.task_settings["SUBJECT_NAME"]} · ' + f'weight: {self.data.task_settings["SUBJECT_WEIGHT"]}g · ' + f'training phase: {training_info["training_phase"]} · ' + f'stimulus gain: {self.data.task_settings["STIM_GAIN"]} · ' + f'reward amount: {self.data.task_settings["REWARD_AMOUNT_UL"]}µl' + ) + except FileNotFoundError: + # there is a chance that people run this directly on another computer for looking at a session, + # in which case the iblrig_settings.yaml are not necessarily on the machine + pass + +
+[docs] + def run(self, file_jsonable: Path | str) -> None: + """ + Watch a jsonable file in conjunction with an iblrigv8 running task (for online use). + + Parameters + ---------- + file_jsonable : Path or str + The sessions jsonable file + """ + file_jsonable = Path(file_jsonable) + self._set_session_string() + self.update_titles() + self.h.fig.canvas.flush_events() + self.real_time = Bunch({'fseek': 0, 'time_last_check': 0}) + flag_file = file_jsonable.parent.joinpath('new_trial.flag') + + while True: + self.h.fig.canvas.draw_idle() + self.h.fig.canvas.flush_events() + time.sleep(0.4) + if not plt.fignum_exists(self.h.fig.number): + break + if flag_file.exists(): + trial_data, bpod_data = load_task_jsonable(file_jsonable, offset=self.real_time.fseek) + new_size = file_jsonable.stat().st_size + for i in np.arange(len(bpod_data)): + self.update_trial(trial_data.iloc[i], bpod_data[i]) + self.real_time.fseek = new_size + self.real_time.time_last_check = time.time() + flag_file.unlink()
+ + +
+[docs] + def display_full_jsonable(self, jsonable_file: Path | str): + trials_table, bpod_data = load_task_jsonable(jsonable_file) + # here we take the end time of the first trial as reference to avoid factoring in the delay + self.data.time_elapsed = bpod_data[-1]['Trial end timestamp'] - bpod_data[0]['Trial end timestamp'] + trials_table['signed_contrast'] = np.sign(trials_table['position']) * trials_table['contrast'] + trials_table['choice'] = trials_table['position'] > 0 + trials_table.loc[~trials_table.trial_correct, 'choice'] = ~trials_table['choice'][~trials_table.trial_correct] + trials_table['contrast'] = trials_table['contrast'].astype( + CategoricalDtype(categories=np.unique(np.r_[-CONTRAST_SET, CONTRAST_SET]), ordered=True) + ) + trials_table['stim_probability_left'] = trials_table['stim_probability_left'].astype( + CategoricalDtype(categories=self.data.probability_set, ordered=True) + ) + self.data.psychometrics = trials_table.groupby(['stim_probability_left', 'signed_contrast']).agg( + count=pd.NamedAgg(column='signed_contrast', aggfunc='count'), + response_time=pd.NamedAgg(column='response_time', aggfunc=np.nanmean), + choice=pd.NamedAgg(column='choice', aggfunc='mean'), + response_time_std=pd.NamedAgg(column='response_time', aggfunc=np.nanstd), + choice_std=pd.NamedAgg(column='choice', aggfunc=np.nanmean), + ) + self.data.ntrials = trials_table.shape[0] + self.data.ntrials_correct = np.sum(trials_table.trial_correct) + self.data.ntrials_nan = self.data.ntrials if self.data.ntrials > 0 else np.nan + self.data.percent_correct = self.data.ntrials_correct / self.data.ntrials_nan * 100 + # agg.water_delivered = trials_table.water_delivered.iloc[-1] + self.data.water_delivered = trials_table.reward_amount.sum() + # init the last trials table + it = self.data.last_trials.index[-np.minimum(self.data.ntrials, NTRIALS_PLOT) :] + self.data.last_trials.loc[it, 'correct'] = trials_table.trial_correct.iloc[-NTRIALS_PLOT:].values + self.data.last_trials.loc[it, 'signed_contrast'] = trials_table.signed_contrast.iloc[-NTRIALS_PLOT:].values + self.data.last_trials.loc[it, 'response_time'] = trials_table.response_time.iloc[-NTRIALS_PLOT:].values + self.data.last_trials.loc[it, 'stim_on'] = np.array( + [bpod_data[i]['States timestamps']['stim_on'][0][0] for i in np.arange(-it.size, 0)] + ) + self.data.last_trials.loc[it, 'play_tone'] = np.array( + [bpod_data[i]['States timestamps']['play_tone'][0][0] for i in np.arange(-it.size, 0)] + ) + self.data.last_trials.loc[it, 'reward_time'] = np.array( + [bpod_data[i]['States timestamps']['reward'][0][0] for i in np.arange(-it.size, 0)] + ) + self.data.last_trials.loc[it, 'error_time'] = np.array( + [bpod_data[i]['States timestamps']['error'][0][0] for i in np.arange(-it.size, 0)] + ) + # we keep only a single column as buffer + self.data.trials_table = trials_table[['response_time']] + self.update_graphics()
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/path_helper.html b/_modules/iblrig/path_helper.html new file mode 100644 index 000000000..f3151866d --- /dev/null +++ b/_modules/iblrig/path_helper.html @@ -0,0 +1,557 @@ + + + + + + iblrig.path_helper — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.path_helper

+import logging
+import os
+import re
+import shutil
+import subprocess
+from pathlib import Path
+from typing import TypeVar
+
+import numpy as np
+import yaml
+from packaging import version
+from pydantic import BaseModel, ValidationError
+
+import iblrig
+from ibllib.io import session_params
+from ibllib.io.raw_data_loaders import load_settings
+from iblrig.constants import HARDWARE_SETTINGS_YAML, RIG_SETTINGS_YAML
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings
+from iblutil.util import Bunch
+from one.alf.spec import is_session_path
+
+log = logging.getLogger(__name__)
+T = TypeVar('T', bound=BaseModel)
+
+
+
+[docs] +def iterate_previous_sessions(subject_name: str, task_name: str, n: int = 1, **kwargs) -> list[dict]: + """ + Iterate over the sessions of a given subject in both the remote and local path and search for a given protocol name. + Return the information of the last n found matching protocols in the form of a dictionary. + + Parameters + ---------- + subject_name : str + Name of the subject. + task_name : str + Name of the protocol to look for in experiment description. + n : int, optional + maximum number of protocols to return + **kwargs + Optional arguments to be passed to iblrig.path_helper.get_local_and_remote_paths + If not used, will use the arguments from iblrig/settings/iblrig_settings.yaml + + Returns + ------- + list[dict] + List of dictionaries with keys: session_path, experiment_description, task_settings, file_task_data + """ + rig_paths = get_local_and_remote_paths(**kwargs) + local_subjects_folder = rig_paths['local_subjects_folder'] + remote_subjects_folder = rig_paths['remote_subjects_folder'] + sessions = _iterate_protocols(local_subjects_folder.joinpath(subject_name), task_name=task_name, n=n) + if remote_subjects_folder is not None: + remote_sessions = _iterate_protocols(remote_subjects_folder.joinpath(subject_name), task_name=task_name, n=n) + if remote_sessions is not None: + sessions.extend(remote_sessions) + # here we rely on the fact that np.unique sort and then we output sessions with the last one first + _, ises = np.unique([s['session_stub'] for s in sessions], return_index=True) + sessions = [sessions[i] for i in np.flipud(ises)] + return sessions
+ + + +def _iterate_protocols(subject_folder: Path, task_name: str, n: int = 1, min_trials: int = 43) -> list[dict]: + """ + Return information on the last n sessions with matching protocol. + + This function iterates over the sessions of a given subject and searches for a given protocol name. + + Parameters + ---------- + subject_folder : Path + A subject folder containing dated folders. + task_name : str + The task protocol name to look for. + n : int + The number of previous protocols to return. + min_trials : int + Skips sessions with fewer than this number of trials. + + Returns + ------- + list[dict] + list of dictionaries with keys: session_stub, session_path, experiment_description, + task_settings, file_task_data. + """ + + def proc_num(x): + """Return protocol number. + + Use 'protocol_number' key if present (unlikely), otherwise use collection name. + """ + i = (x or {}).get('collection', '00').split('_') + collection_int = int(i[-1]) if i[-1].isnumeric() else 0 + return x.get('protocol_number', collection_int) + + protocols = [] + if subject_folder is None or Path(subject_folder).exists() is False: + return protocols + sessions = subject_folder.glob('????-??-??/*/_ibl_experiment.description*.yaml') # seq may be X or XXX + # Make extra sure to only include valid sessions + sessions = filter(lambda x: is_session_path(x.relative_to(subject_folder.parent).parent), sessions) + for file_experiment in sorted(sessions, reverse=True): + session_path = file_experiment.parent + ad = session_params.read_params(file_experiment) + # reversed: we look for the last task first if the protocol ran twice + tasks = filter(None, map(lambda x: x.get(task_name), ad.get('tasks', []))) + for adt in sorted(tasks, key=proc_num, reverse=True): + if not (task_settings := load_settings(session_path, task_collection=adt['collection'])): + continue + if task_settings.get('NTRIALS', min_trials + 1) < min_trials: # ignore sessions with too few trials + continue + protocols.append( + Bunch( + { + 'session_stub': '_'.join(file_experiment.parent.parts[-2:]), # 2019-01-01_001 + 'session_path': file_experiment.parent, + 'task_collection': adt['collection'], + 'experiment_description': ad, + 'task_settings': task_settings, + 'file_task_data': session_path.joinpath(adt['collection'], '_iblrig_taskData.raw.jsonable'), + } + ) + ) + if len(protocols) >= n: + return protocols + return protocols + + +
+[docs] +def get_local_and_remote_paths( + local_path: str | Path | None = None, remote_path: str | Path | None = None, lab: str | None = None, iblrig_settings=None +) -> dict: + """ + Function used to parse input arguments to transfer commands. + + If the arguments are None, reads in the settings and returns the values from the files. + local_subjects_path always has a fallback on the home directory / iblrig_data + remote_subjects_path has no fallback and will return None when all options are exhausted + :param local_path: + :param remote_path: + :param lab: + :param iblrig_settings: if provided, settings dictionary, otherwise will load the default settings files + :return: dictionary, with following keys (example output) + {'local_data_folder': PosixPath('C:/iblrigv8_data'), + 'remote_data_folder': PosixPath('Y:/'), + 'local_subjects_folder': PosixPath('C:/iblrigv8_data/mainenlab/Subjects'), + 'remote_subjects_folder': PosixPath('Y:/Subjects')} + """ + # we only want to attempt to load the settings file if necessary + if (local_path is None) or (remote_path is None) or (lab is None): + iblrig_settings = load_pydantic_yaml(RigSettings) if iblrig_settings is None else iblrig_settings + + paths = Bunch({'local_data_folder': local_path, 'remote_data_folder': remote_path}) + if paths.local_data_folder is None: + paths.local_data_folder = ( + Path(p) if (p := iblrig_settings['iblrig_local_data_path']) else Path.home().joinpath('iblrig_data') + ) + elif isinstance(paths.local_data_folder, str): + paths.local_data_folder = Path(paths.local_data_folder) + if paths.remote_data_folder is None: + paths.remote_data_folder = Path(p) if (p := iblrig_settings['iblrig_remote_data_path']) else None + elif isinstance(paths.remote_data_folder, str): + paths.remote_data_folder = Path(paths.remote_data_folder) + + # Get the subjects folders. If not defined in the settings, assume local_data_folder + /Subjects + paths.local_subjects_folder = (iblrig_settings or {}).get('iblrig_local_subjects_path', None) + lab = lab or (iblrig_settings or {}).get('ALYX_LAB', None) + if paths.local_subjects_folder is None: + if paths.local_data_folder.name == 'Subjects': + paths.local_subjects_folder = paths.local_data_folder + elif lab: # append lab/Subjects part + paths.local_subjects_folder = paths.local_data_folder.joinpath(lab, 'Subjects') + else: # NB: case is important here. ALF spec expects lab folder before 'Subjects' (capitalized) + paths.local_subjects_folder = paths.local_data_folder.joinpath('subjects') + else: + paths.local_subjects_folder = Path(paths.local_subjects_folder) + + # Get the remote subjects folders. If not defined in the settings, assume remote_data_folder + /Subjects + paths.remote_subjects_folder = (iblrig_settings or {}).get('iblrig_remote_subjects_path', None) + if paths.remote_subjects_folder is None: + if paths.remote_data_folder: + if paths.remote_data_folder.name == 'Subjects': + paths.remote_subjects_folder = paths.remote_data_folder + else: + paths.remote_subjects_folder = paths.remote_data_folder.joinpath('Subjects') + else: + paths.remote_subjects_folder = Path(paths.remote_subjects_folder) + return paths
+ + + +def _load_settings_yaml(filename: Path | str = RIG_SETTINGS_YAML, do_raise: bool = True) -> Bunch: + filename = Path(filename) + if not filename.is_absolute(): + filename = Path(iblrig.__file__).parents[1].joinpath('settings', filename) + if not filename.exists() and not do_raise: + log.error(f'File not found: {filename}') + return Bunch() + with open(filename) as fp: + rs = yaml.safe_load(fp) + rs = patch_settings(rs, filename.stem) + return Bunch(rs) + + +
+[docs] +def load_pydantic_yaml(model: type[T], filename: Path | str | None = None, do_raise: bool = True) -> T: + """ + Load YAML data from a specified file or a standard IBLRIG settings file, + validate it using a Pydantic model, and return the validated Pydantic model + instance. + + Parameters + ---------- + model : Type[T] + The Pydantic model class to validate the YAML data against. + filename : Path | str | None, optional + The path to the YAML file. + If None (default), the function deduces the appropriate standard IBLRIG + settings file based on the model. + do_raise : bool, optional + If True (default), raise a ValidationError if validation fails. + If False, log the validation error and construct a model instance + with the provided data. Defaults to True. + + Returns + ------- + T + An instance of the Pydantic model, validated against the YAML data. + + Raises + ------ + ValidationError + If validation fails and do_raise is set to True. + The raised exception contains details about the validation error. + TypeError + If the filename is None and the model class is not recognized as + HardwareSettings or RigSettings. + """ + if filename is None: + if model == HardwareSettings: + filename = HARDWARE_SETTINGS_YAML + elif model == RigSettings: + filename = RIG_SETTINGS_YAML + else: + raise TypeError(f'Cannot deduce filename for model `{model.__name__}`.') + if filename not in (HARDWARE_SETTINGS_YAML, RIG_SETTINGS_YAML): + # TODO: We currently skip validation of pydantic models if an extra + # filename is provided that does NOT correspond to the standard + # settings files of IBLRIG. This should be re-evaluated. + do_raise = False + rs = _load_settings_yaml(filename=filename, do_raise=do_raise) + try: + return model.model_validate(rs) + except ValidationError as e: + if not do_raise: + log.exception(e) + return model.model_construct(**rs) + else: + raise e
+ + + +
+[docs] +def save_pydantic_yaml(data: T, filename: Path | str | None = None) -> None: + if filename is None: + if isinstance(data, HardwareSettings): + filename = HARDWARE_SETTINGS_YAML + elif isinstance(data, RigSettings): + filename = RIG_SETTINGS_YAML + else: + raise TypeError(f'Cannot deduce filename for model `{type(data).__name__}`.') + else: + filename = Path(filename) + yaml_data = data.model_dump() + data.model_validate(yaml_data) + with open(filename, 'w') as f: + log.debug(f'Dumping {type(data).__name__} to {filename.name}') + yaml.dump(yaml_data, f, sort_keys=False)
+ + + +
+[docs] +def patch_settings(rs: dict, filename: str | Path) -> dict: + """ + Update loaded settings files to ensure compatibility with latest version. + + Parameters + ---------- + rs : dict + A loaded settings file. + filename : str | Path + The filename of the settings file. + + Returns + ------- + dict + The updated settings. + """ + filename = Path(filename) + settings_version = version.parse(rs.get('VERSION', '0.0.0')) + if filename.stem.startswith('hardware'): + if settings_version < version.Version('1.0.0') and 'device_camera' in rs: + log.info('Patching hardware settings; assuming left camera label') + rs['device_cameras'] = {'left': rs.pop('device_camera')} + rs['VERSION'] = '1.0.0' + if 'device_cameras' in rs and rs['device_cameras'] is not None: + rs['device_cameras'] = {k: v for k, v in rs['device_cameras'].items() if v} # remove empty keys + idx_missing = set(rs['device_cameras']) == {'left'} and 'INDEX' not in rs['device_cameras']['left'] + if settings_version < version.Version('1.1.0') and idx_missing: + log.info('Patching hardware settings; assuming left camera index and training workflow') + workflow = rs['device_cameras']['left'].pop('BONSAI_WORKFLOW', None) + bonsai_workflows = {'setup': 'devices/camera_setup/setup_video.bonsai', 'recording': workflow} + rs['device_cameras'] = { + 'training': {'BONSAI_WORKFLOW': bonsai_workflows, 'left': {'INDEX': 1, 'SYNC_LABEL': 'audio'}} + } + rs['VERSION'] = '1.1.0' + if rs.get('device_cameras') is None: + rs['device_cameras'] = {} + return rs
+ + + +
+[docs] +def get_commit_hash(folder: str): + here = os.getcwd() + os.chdir(folder) + out = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode().strip() + os.chdir(here) + if not out: + log.debug('Commit hash is empty string') + log.debug(f'Found commit hash {out}') + return out
+ + + +
+[docs] +def iterate_collection(session_path: str, collection_name='raw_task_data') -> str: + """ + Given a session path returns the next numbered collection name. + + Parameters + ---------- + session_path : str + The session path containing zero or more numbered collections. + collection_name : str + The collection name without the _NN suffix. + + Returns + ------- + str + The next numbered collection name. + + Examples + -------- + In a folder where there are no raw task data folders + + >>> iterate_collection('./subject/2020-01-01/001') + 'raw_task_data_00' + + In a folder where there is one raw_imaging_data_00 folder + + >>> iterate_collection('./subject/2020-01-01/001', collection_name='raw_imaging_data') + 'raw_imaging_data_01' + """ + if not Path(session_path).exists(): + return f'{collection_name}_00' + collections = filter(Path.is_dir, Path(session_path).iterdir()) + collection_names = map(lambda x: x.name, collections) + tasks = sorted(filter(re.compile(f'{collection_name}' + '_[0-9]{2}').match, collection_names)) + if len(tasks) == 0: + return f'{collection_name}_00' + return f'{collection_name}_{int(tasks[-1][-2:]) + 1:02}'
+ + + +
+[docs] +def create_bonsai_layout_from_template(workflow_file: Path) -> None: + """ + Create a Bonsai layout file from a template if it does not already exist. + + If the file with the suffix `.bonsai.layout` does not exist for the given + workflow file, this function will attempt to create it from a template + file with the suffix `.bonsai.layout_template`. If the template file also + does not exist, the function logs that no template layout is available. + + Background: Bonsai stores dialog settings (window position, control + visibility, etc.) in an XML file with the suffix `.bonsai.layout`. These + layout files are user-specific and may be overwritten locally by the user + according to their preferences. To ensure that a default layout is + available, a template file with the suffix `.bonsai.layout_template` can + be provided as a starting point. + + Parameters + ---------- + workflow_file : Path + The path to the Bonsai workflow for which the layout is to be created. + + Raises + ------ + FileNotFoundError + If the provided workflow_file does not exist. + """ + if not workflow_file.exists(): + raise FileNotFoundError(workflow_file) + if not (layout_file := workflow_file.with_suffix('.bonsai.layout')).exists(): + template_file = workflow_file.with_suffix('.bonsai.layout_template') + if template_file.exists(): + log.info(f'Creating default {layout_file.name}') + shutil.copy(template_file, layout_file) + else: + log.debug(f'No template layout for {workflow_file.name}')
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/pydantic_definitions.html b/_modules/iblrig/pydantic_definitions.html new file mode 100644 index 000000000..d6da5b1ad --- /dev/null +++ b/_modules/iblrig/pydantic_definitions.html @@ -0,0 +1,442 @@ + + + + + + iblrig.pydantic_definitions — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.pydantic_definitions

+from collections import abc
+from datetime import date
+from pathlib import Path
+from typing import Annotated, Literal
+
+import pandas as pd
+from annotated_types import Ge, Le
+from pydantic import (
+    AnyUrl,
+    BaseModel,
+    ConfigDict,
+    DirectoryPath,
+    Field,
+    FilePath,
+    PlainSerializer,
+    PositiveFloat,
+    PositiveInt,
+    field_serializer,
+    field_validator,
+)
+from pydantic_core._pydantic_core import PydanticUndefined
+
+from iblrig.constants import BASE_PATH
+
+ExistingFilePath = Annotated[FilePath, PlainSerializer(lambda s: str(s), return_type=str)]
+"""Validate that path exists and is file. Cast to str upon save."""
+
+BehaviourInputPort = Annotated[int, Ge(1), Le(4)]
+
+
+
+[docs] +class BunchModel(BaseModel, abc.MutableMapping): + def __getitem__(self, key): + return getattr(self, key) + + def __setitem__(self, key, value): + setattr(self, key, value) + + def __len__(self): + return len(self.__dict__) + + def __iter__(self): + return iter(self.model_fields.keys()) + +
+[docs] + def items(self): + return [(key, getattr(self, key)) for key in self.keys()]
+ + +
+[docs] + def keys(self): + return self.model_fields.keys()
+ + +
+[docs] + def values(self): + return (getattr(self, key) for key in self.keys())
+ + + def __delitem__(self, key): + raise NotImplementedError
+ + + +
+[docs] +class RigSettings(BunchModel, validate_assignment=True): + model_config = ConfigDict(title='iblrig_settings.yaml') + iblrig_local_data_path: Path | None = Field( + title='IBLRIG local data path', description='The local folder IBLRIG should use for storing data' + ) + iblrig_local_subjects_path: DirectoryPath | None = Field( + title='IBLRIG full local data path', + default=None, + description='An optional full local data folder (including /Subjects)', + ) + iblrig_remote_data_path: Path | bool | None = Field( + title='IBLRIG remote data path', description='The remote folder IBLRIG should use for storing data' + ) + iblrig_remote_subjects_path: Path | None = Field( + title='IBLRIG full remote data path', + default=None, + description='An optional full remote data folder (including /Subjects)', + ) + ALYX_USER: str | None = Field(description='Your Alyx username') + ALYX_URL: AnyUrl | None = Field(title='Alyx URL', description='The URL to your Alyx database') + ALYX_LAB: str | None = Field(description="Your lab's name as registered on the Alyx database") + +
+[docs] + @field_validator('ALYX_USER', 'ALYX_LAB') + def str_must_not_contain_space(cls, v): # noqa: N805 + if isinstance(v, str) and ' ' in v: + raise ValueError('must not contain a space') + return v
+ + +
+[docs] + @field_validator('iblrig_remote_data_path') + def validate_remote_data_path(cls, v): # noqa: N805 + if isinstance(v, bool) and v: + raise ValueError() + return v
+
+ + + +
+[docs] +class HardwareSettingsBpod(BunchModel): + COM_BPOD: str | None + BPOD_TTL_TEST_DATE: date | None = None + BPOD_TTL_TEST_STATUS: str | None = None + SOUND_BOARD_BPOD_PORT: Literal['Serial1', 'Serial2', 'Serial3', 'Serial4', 'Serial5', None] = None + ROTARY_ENCODER_BPOD_PORT: Literal['Serial1', 'Serial2', 'Serial3', 'Serial4', 'Serial5', None] = None + DISABLE_BEHAVIOR_INPUT_PORTS: list[BehaviourInputPort] = [2, 3, 4]
+ + + +
+[docs] +class HardwareSettingsFrame2TTL(BunchModel): + COM_F2TTL: str | None + F2TTL_CALIBRATION_DATE: date | None + F2TTL_DARK_THRESH: int + F2TTL_LIGHT_THRESH: int
+ + + +
+[docs] +class HardwareSettingsRotaryEncoder(BunchModel): + COM_ROTARY_ENCODER: str | None
+ + + +
+[docs] +class HardwareSettingsScreen(BunchModel): + DISPLAY_IDX: int = Field(ge=0, le=1) # -1 = Default, 0 = First, 1 = Second, 2 = Third, etc + SCREEN_FREQ_TARGET: int = Field(gt=0) + SCREEN_FREQ_TEST_DATE: date | None = None + SCREEN_FREQ_TEST_STATUS: str | None = None + SCREEN_LUX_DATE: date | None = None + SCREEN_LUX_VALUE: float | None = None
+ + + +
+[docs] +class HardwareSettingsSound(BunchModel): + OUTPUT: Literal['harp', 'xonar', 'hifi', 'sysdefault'] + COM_SOUND: str | None = None + AMP_TYPE: Literal['harp', 'AMP2X15'] | None = None
+ + # ATTENUATION_DB: float = Field(default=0, le=0) + + +
+[docs] +class HardwareSettingsValve(BunchModel): + WATER_CALIBRATION_DATE: date + WATER_CALIBRATION_RANGE: list[PositiveFloat] = Field(min_length=2, max_length=2) # type: ignore + WATER_CALIBRATION_N: PositiveInt = Field(ge=3, default=5) + WATER_CALIBRATION_OPEN_TIMES: list[PositiveFloat] = Field(min_length=2) # type: ignore + WATER_CALIBRATION_WEIGHT_PERDROP: list[float] = Field(PositiveFloat, min_length=2) # type: ignore + FREE_REWARD_VOLUME_UL: PositiveFloat = 1.5
+ + + +
+[docs] +class HardwareSettingsScale(BunchModel): + COM_SCALE: str | None = None
+ + + +
+[docs] +class HardwareSettingsCamera(BunchModel): + INDEX: int + FPS: PositiveInt | None = Field( + title='Camera frame rate', + default=None, + description='An optional frame rate (for camera QC only)', + ) + WIDTH: PositiveInt | None = Field( + title='Camera frame width', + default=None, + description='An optional frame width (for camera QC only)', + ) + HEIGHT: PositiveInt | None = Field( + title='Camera frame height', + default=None, + description='An optional frame hight (for camera QC only)', + ) + SYNC_LABEL: str | None = Field( + title='Camera DAQ sync label', + default=None, + description='The name of the DAQ channel wired to the camera GPIO', + )
+ + + +
+[docs] +class HardwareSettingsCameraWorkflow(BunchModel): + setup: ExistingFilePath | None = Field( + title='Optional camera setup workflow', + default=None, + description='An optional path to the camera setup Bonsai workflow.', + ) + recording: ExistingFilePath = Field( + title='Camera recording workflow', description='The path to the Bonsai workflow for camera recording.' + ) + +
+[docs] + @field_validator('setup', 'recording', mode='before') + def valid_path(cls, v): # noqa: N805 + if not Path(v).is_absolute(): # assume relative to iblrig repo + v = BASE_PATH.joinpath(v) + return v
+
+ + + +
+[docs] +class HardwareSettingsMicrophone(BunchModel): + BONSAI_WORKFLOW: Path + +
+[docs] + @field_serializer('BONSAI_WORKFLOW') + def serialize_path(self, bonsai_workflow: Path, _info): + return str(bonsai_workflow)
+
+ + + +
+[docs] +class HardwareSettings(BunchModel): + model_config = ConfigDict(title='hardware_settings.yaml') + RIG_NAME: str + MAIN_SYNC: bool + device_bpod: HardwareSettingsBpod + device_frame2ttl: HardwareSettingsFrame2TTL + device_rotary_encoder: HardwareSettingsRotaryEncoder + device_screen: HardwareSettingsScreen + device_sound: HardwareSettingsSound + device_valve: HardwareSettingsValve + device_scale: HardwareSettingsScale = HardwareSettingsScale() + device_cameras: dict[str, dict[str, HardwareSettingsCameraWorkflow | HardwareSettingsCamera]] | None + device_microphone: HardwareSettingsMicrophone | None = None + VERSION: str
+ + + +
+[docs] +class TrialDataModel(BaseModel): + """ + A data model for trial data that extends BaseModel. + + This model allows for the addition of extra fields beyond those defined in the model. + """ + + model_config = ConfigDict(extra='allow') # allow adding extra fields + +
+[docs] + @classmethod + def preallocate_dataframe(cls, n_rows: int) -> pd.DataFrame: + """ + Preallocate a DataFrame with specified number of rows, using default values or pandas.NA. + + This method creates a pandas DataFrame with the same columns as the fields defined in the Pydantic model. + Each column is initialized with the field's default value if available, otherwise with pandas.NA. + + We use Pandas.NA for default values rather than NaN, None or Zero. This allows us to clearly indicate missing + values - which will raise a Pydantic ValidationError. + + Parameters + ---------- + n_rows : int + The number of rows to create in the DataFrame. + + Returns + ------- + pd.DataFrame + A DataFrame with `n_rows` rows and columns corresponding to the model's fields. + """ + data = {} + for field, field_info in cls.model_fields.items(): + default_value = field_info.default if field_info.default is not PydanticUndefined else pd.NA + data[field] = [default_value] * n_rows + return pd.DataFrame(data)
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/raw_data_loaders.html b/_modules/iblrig/raw_data_loaders.html new file mode 100644 index 000000000..706c7caca --- /dev/null +++ b/_modules/iblrig/raw_data_loaders.html @@ -0,0 +1,178 @@ + + + + + + iblrig.raw_data_loaders — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.raw_data_loaders

+import json
+import logging
+from pathlib import Path
+from typing import Any
+
+import pandas as pd
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +def load_task_jsonable(jsonable_file: str | Path, offset: int | None = None) -> tuple[pd.DataFrame, list[Any]]: + """ + Reads in a task data jsonable file and returns a trials dataframe and a bpod data list. + + Parameters + ---------- + - jsonable_file (str): full path to jsonable file. + - offset (int or None): The offset to start reading from (default: None). + + Returns + ------- + - tuple: A tuple containing: + - trials_table (pandas.DataFrame): A DataFrame with the trial info in the same format as the Session trials table. + - bpod_data (list): timing data for each trial + """ + trials_table = [] + with open(jsonable_file) as f: + if offset is not None: + f.seek(offset, 0) + for line in f: + trials_table.append(json.loads(line)) + + # pop-out the bpod data from the table + bpod_data = [] + for td in trials_table: + bpod_data.append(td.pop('behavior_data')) + + trials_table = pd.DataFrame(trials_table) + return trials_table, bpod_data
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/rig_component.html b/_modules/iblrig/rig_component.html new file mode 100644 index 000000000..89ac0d7c6 --- /dev/null +++ b/_modules/iblrig/rig_component.html @@ -0,0 +1,185 @@ + + + + + + iblrig.rig_component — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.rig_component

+from abc import ABC, abstractmethod
+
+from pydantic import BaseModel
+
+from iblrig.hardware_validation import Validator
+
+
+
+[docs] +class RigComponent(ABC): + @property + @abstractmethod + def pretty_name(self) -> str: + """ + Get the component's pretty name. + + Returns + ------- + str + A user-friendly name of the component. + """ + ... + + @property + @abstractmethod + def validator(self) -> Validator: + """ + Get the component's validator. + + Returns + ------- + Validator + The validator instance associated with the component. + """ + ... + + @property + @abstractmethod + def settings(self) -> BaseModel: + """ + Get the component's settings. + + Returns + ------- + BaseModel + The pydantic model for the component's settings. + """ + ...
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/scale.html b/_modules/iblrig/scale.html new file mode 100644 index 000000000..f747f1d69 --- /dev/null +++ b/_modules/iblrig/scale.html @@ -0,0 +1,262 @@ + + + + + + iblrig.scale — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.scale

+import logging
+import re
+from dataclasses import dataclass
+
+from iblrig.serial_singleton import SerialSingleton
+
+log = logging.getLogger(__name__)
+
+# http://dmx.ohaus.com/WorkArea/downloadasset.aspx?id=3600
+# https://dmx.ohaus.com/WorkArea/showcontent.aspx?id=4294974227
+RE_PATTERN = re.compile(rb'\s*(\S+)\s+(\w+)\s(.)\s{1,3}(\w{0,2})')
+
+
+
+[docs] +@dataclass +class ScaleData: + weight: float = float('nan') + unit: str = 'g' + stable: bool = False + mode: str = ''
+ + + +
+[docs] +class Scale(SerialSingleton): +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, baudrate=9600, timeout=5, **kwargs) + self.assert_setting('ON') + while self.query_line('1M') == b'ES': + pass + self.assert_setting('1M') # set current application mode to WEIGH + self.assert_setting('1U') # set unit to grams + self.assert_setting('0FMT') # use New Scout print format + log.debug(f'Connected to OHAUS scale on {self.portstr}')
+ + +
+[docs] + def assert_setting(self, query: str, expected_response: str = b'OK!', do_raise: bool = True) -> bool: + success = self.query_line(query) == expected_response + if do_raise and not success: + raise AssertionError + return success
+ + +
+[docs] + def query_line(self, query: str) -> bytes: + self.reset_input_buffer() + self.write(query + '\r\n') + return self.readline().rstrip(b'\r\n')
+ + +
+[docs] + def zero(self) -> bool: + success = self.assert_setting('Z', do_raise=False) + if success: + self.get_stable_grams() + return success
+ + +
+[docs] + def tare(self) -> bool: + weight, _, _, mode = self._split_query() + if weight == b'0.00' and mode != b'N': + return True + success = self.assert_setting('T', do_raise=False) + if success: + self.get_stable_grams() + return success
+ + + @property + def grams(self) -> float: + return self.get_grams()[0] + +
+[docs] + def get_stable_grams(self) -> float: + """ + Blocking function that will only return a weight reading once the scale is stable. + + Returns + ------- + float + Stable weight reading (grams) + + """ + while not (return_value := self.get_grams())[1]: + pass + return return_value[0]
+ + + def _split_query(self, query: str = 'IP') -> tuple[bytes, ...]: + data = self.query_line(query) + if (match := re.fullmatch(RE_PATTERN, data)) is None: + return b'nan', b'g', b'?', b'' + else: + return match.groups() + +
+[docs] + def get_grams(self) -> tuple[float, bool]: + """ + Obtain weight reading in grams and stability indicator. + + Returns + ------- + float + Weight reading in grams + bool + Stability indicator: True if scale is stable, False if not + """ + weight, unit, stable, _ = self._split_query('IP') + if unit != b'g': + self.assert_setting('1U') + return self.get_grams() + return float(weight), stable == b' '
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/serial_singleton.html b/_modules/iblrig/serial_singleton.html new file mode 100644 index 000000000..11719b414 --- /dev/null +++ b/_modules/iblrig/serial_singleton.html @@ -0,0 +1,513 @@ + + + + + + iblrig.serial_singleton — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.serial_singleton

+import ctypes
+import logging
+import re
+import struct
+import threading
+from collections.abc import Generator
+from typing import Any, overload
+
+import numpy as np
+import serial
+from serial.serialutil import to_bytes  # type: ignore[attr-defined]
+from serial.tools import list_ports
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class SerialSingletonException(serial.SerialException): + pass
+ + + +
+[docs] +class SerialSingleton(serial.Serial): + _instances: dict[str | None, serial.Serial] = dict() + _initialized = False + _lock = threading.RLock() + +
+[docs] + def __new__(cls, port: str | None = None, serial_number: str | None = None, *args, **kwargs): + # identify the device by its serial number + if port is None: + if serial_number is not None: + port = get_port_from_serial_number(serial_number) + if port is None: + raise SerialSingletonException(f'No device matching serial number `{serial_number}`') + else: + raise ValueError('Neither port nor serial number provided') + + # implement singleton + with cls._lock: + instance = SerialSingleton._instances.get(port, None) + if instance is None: + log.debug(f'Creating new {cls.__name__} instance on {port}') + instance = super().__new__(cls) + SerialSingleton._instances[port] = instance + else: + instance_name = type(instance).__name__ + if instance_name != cls.__name__: + raise SerialSingletonException(f'{port} is already in use by an instance of {instance_name}') + log.debug(f'Using existing {instance_name} instance on {port}') + return instance
+ + +
+[docs] + def __init__(self, port: str | None = None, connect: bool = True, **kwargs) -> None: + if not self._initialized: + super().__init__(**kwargs) + serial.Serial.port.fset(self, port) # type: ignore[attr-defined] + self.port_info = next((p for p in list_ports.comports() if p.device == self.port), None) + self._initialized = True + if not getattr(self, 'is_open', False) and connect is True: + self.open()
+ + + def __del__(self) -> None: + self.close() + with self._lock: + if hasattr(self, 'port') and self.port in SerialSingleton._instances: + log.debug(f'Deleting {type(self).__name__} instance on {self.port}') + SerialSingleton._instances.pop(self.port) + +
+[docs] + def open(self) -> None: + if self.port is not None: + super().open() + log.debug(f'Serial connection to {self.port} opened')
+ + +
+[docs] + def close(self) -> None: + if getattr(self, 'is_open', False): + super().close() + log.debug(f'Serial connection to {self.port} closed')
+ + + @property + def port(self) -> str | None: + """ + Get the serial device's communication port. + + Returns + ------- + str + The serial port (e.g., 'COM3', '/dev/ttyUSB0') used by the serial device. + """ + return super().port + + @port.setter + def port(self, port: str | None): + """ + Set the serial device's communication port. + + This setter allows changing the communication port before the object is + instantiated. Once the object is instantiated, attempting to change the port + will raise a SerialSingletonException. + + Parameters + ---------- + port : str + The new communication port to be set (e.g., 'COM3', '/dev/ttyUSB0'). + + Raises + ------ + SerialSingletonException + If an attempt is made to change the port after the object has been + instantiated. + """ + if self._initialized: + raise SerialSingletonException('Port cannot be changed after instantiation.') + if port is not None: + serial.Serial.port.fset(self, port) # type: ignore[attr-defined] + +
+[docs] + def write(self, data) -> int | None: + return super().write(self.to_bytes(data))
+ + +
+[docs] + def write_packed(self, format_string: str, *data: Any) -> int | None: + """ + Pack values according to format string and write to serial device. + + Parameters + ---------- + format_string : str + Format string describing the data layout for packing the data + following the conventions of the :mod:`struct` module. + See https://docs.python.org/3/library/struct.html#format-characters + + data : Any + Data to be written to the serial device. + + Returns + ------- + int or None + Number of bytes written to the serial device. + """ + size = struct.calcsize(format_string) + buffer = ctypes.create_string_buffer(size) + struct.pack_into(format_string, buffer, 0, *data) + return super().write(buffer)
+ + + @overload + def read(self, data_specifier: int = 1) -> bytes: ... + + @overload + def read(self, data_specifier: str) -> tuple[Any, ...]: ... + +
+[docs] + def read(self, data_specifier=1): + r""" + Read data from the serial device. + + Parameters + ---------- + data_specifier : int or str, default: 1 + The number of bytes to receive from the serial device, or a format string + for unpacking. + + When providing an integer, the specified number of bytes will be returned + as a bytestring. When providing a `format string`, the data will be + unpacked into a tuple accordingly. Format strings follow the conventions of + the :mod:`struct` module. + + .. _format string: + https://docs.python.org/3/library/struct.html#format-characters + + Returns + ------- + bytes or tuple[Any] + Data returned by the serial device. By default, data is formatted as a + bytestring. Alternatively, when provided with a format string, data will + be unpacked into a tuple according to the specified format string. + """ + if isinstance(data_specifier, str): + n_bytes = struct.calcsize(data_specifier) + return struct.unpack(data_specifier, super().read(n_bytes)) + else: + return super().read(data_specifier)
+ + + @overload + def query(self, query: Any, data_specifier: int = 1) -> bytes: ... + + @overload + def query(self, query: Any, data_specifier: str) -> tuple[Any, ...]: ... + +
+[docs] + def query(self, query, data_specifier=1): + r""" + Query data from the serial device. + + This method is a combination of :py:meth:`write` and :py:meth:`read`. + + Parameters + ---------- + query : Any + Query to be sent to the serial device. + data_specifier : int or str, default: 1 + The number of bytes to receive from the serial device, or a format string + for unpacking. + + When providing an integer, the specified number of bytes will be returned + as a bytestring. When providing a `format string`_, the data will be + unpacked into a tuple accordingly. Format strings follow the conventions of + the :py:mod:`struct` module. + + .. _format string: + https://docs.python.org/3/library/struct.html#format-characters + + Returns + ------- + bytes or tuple[Any] + Data returned by the serial device. By default, data is formatted as a + bytestring. Alternatively, when provided with a format string, data will be + unpacked into a tuple according to the specified format string. + """ + self.write(query) + return self.read(data_specifier)
+ + +
+[docs] + @staticmethod + def to_bytes(data: Any) -> bytes: + """ + Convert data to bytestring. + + This method extends :meth:`serial.to_bytes` with support for NumPy types, + strings (interpreted as utf-8) and lists. + + Parameters + ---------- + data : Any + Data to be converted to bytestring. + + Returns + ------- + bytes + Data converted to bytestring. + """ + match data: + case np.ndarray() | np.generic(): + return data.tobytes() + case int(): + return data.to_bytes(1, 'little') + case str(): + return data.encode('utf-8') + case list(): + return b''.join([SerialSingleton.to_bytes(item) for item in data]) + case _: + return to_bytes(data) # type: ignore[no-any-return]
+
+ + + +
+[docs] +def filter_ports(**kwargs: dict[str, Any]) -> Generator[str, None, None]: + """ + Filter serial ports based on specified criteria. + + Parameters + ---------- + **kwargs : keyword arguments + Filtering criteria for serial ports. Each keyword should correspond + to an attribute of the serial port object (ListPortInfo). The values associated + with the keywords are used to filter the ports based on various conditions. + + Yields + ------ + str + The device name of a filtered serial port that meets all specified criteria. + + Examples + -------- + To filter ports by manufacturer and product: + + >>> for port in filter_ports(manufacturer="Arduino", product="Uno"): + ... print(port) + + Raises + ------ + ValueError + If a specified attribute does not exist for a port. + + Notes + ----- + - The function uses regular expressions for string matching when both actual + and expected values are strings. + """ + for port in list_ports.comports(): + yield_port = True + for key, expected_value in kwargs.items(): + if not hasattr(port, key): + raise ValueError(f"Attribute '{key}' not found for port {port}") + actual_value = getattr(port, key) + if isinstance(actual_value, str) and isinstance(expected_value, str): + if bool(re.search(expected_value, actual_value)): + continue + elif actual_value == expected_value: + continue + yield_port = False + break + if yield_port: + yield port.device
+ + + +
+[docs] +def get_port_from_serial_number(serial_number: str) -> str | None: + """ + Retrieve the com port of a USB serial device identified by its serial number. + + Parameters + ---------- + serial_number : str + The serial number of the USB device that you want to obtain the communication + port of. + + Returns + ------- + str or None + The communication port of the USB serial device that matches the serial number + provided by the user. The function will return None if no such device was found. + """ + port_info = list_ports.comports() + port_match = next((p for p in port_info if p.serial_number == serial_number), None) + return port_match.name if port_match else None
+ + + +
+[docs] +def get_serial_number_from_port(port: str | None) -> str | None: + """ + Retrieve the serial number of a USB serial device identified by its com port. + + Parameters + ---------- + port : str + The communication port of the USB serial device for which you want to retrieve + the serial number. + + Returns + ------- + str or None + The serial number of the USB serial device corresponding to the provided + communication port. Returns None if no device matches the port. + """ + port_info = list_ports.comports() + port_match = next((p for p in port_info if p.name == port), None) + return port_match.serial_number if port_match else None
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/session_creator.html b/_modules/iblrig/session_creator.html new file mode 100644 index 000000000..482a51960 --- /dev/null +++ b/_modules/iblrig/session_creator.html @@ -0,0 +1,191 @@ + + + + + + iblrig.session_creator — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.session_creator

+"""Creates sessions, pre-generates stim and ephys sessions."""
+
+import numpy as np
+
+from iblrig import misc
+
+
+
+[docs] +def draw_position(position_set, stim_probability_left) -> int: + return int(np.random.choice(position_set, p=[stim_probability_left, 1 - stim_probability_left]))
+ + + +
+[docs] +def draw_block_len(factor, min_=20, max_=100): + return int(misc.truncated_exponential(scale=factor, min_value=min_, max_value=max_))
+ + + +# EPHYS CHOICE WORLD +
+[docs] +def make_ephyscw_pc(prob_type='biased'): + """ + Create positions, contrasts and block lengths for ephysCW. + + Generates ~2000 trials. + + Parameters + ---------- + prob_type : str + 'biased': 0 contrast half has likely to be drawn, 'uniform': 0 contrast as likely as other contrasts + """ + contrasts = [1.0, 0.25, 0.125, 0.0625, 0.0] + len_block = [90] + pos = [-35] * int(len_block[0] / 2) + [35] * int(len_block[0] / 2) + cont = np.sort(contrasts * 10)[::-1][:-5].tolist() + prob = [0.5] * len_block[0] + pc = np.array([pos, cont + cont, prob]).T + np.random.shuffle(pc) # only shuffles on the first dimension + + prob_left = 0.8 if draw_position([-35, 35], 0.5) < 0 else 0.2 + while len(pc) < 2001: + len_block.append(draw_block_len(60, min_=20, max_=100)) + for _x in range(len_block[-1]): + p = draw_position([-35, 35], prob_left) + c = misc.draw_contrast(contrasts, probability_type=prob_type) + pc = np.append(pc, np.array([[p, c, prob_left]]), axis=0) + # do this in PC space + prob_left = np.round(np.abs(1 - prob_left), 1) + + return pc, len_block
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/sound.html b/_modules/iblrig/sound.html new file mode 100644 index 000000000..1a51b113a --- /dev/null +++ b/_modules/iblrig/sound.html @@ -0,0 +1,273 @@ + + + + + + iblrig.sound — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.sound

+import logging
+
+import numpy as np
+
+from pybpod_soundcard_module.module_api import DataType, SampleRate, SoundCardModule
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +def make_sound(rate=44100, frequency=5000, duration=0.1, amplitude=1, fade=0.01, chans='L+TTL'): + """ + Build sounds and save bin file for upload to soundcard or play via + sounddevice lib. + + :param rate: sample rate of the soundcard use 96000 for Bpod, + defaults to 44100 for soundcard + :type rate: int, optional + :param frequency: (Hz) of the tone, if -1 will create uniform random white + noise, defaults to 10000 + :type frequency: int, optional + :param duration: (s) of sound, defaults to 0.1 + :type duration: float, optional + :param amplitude: E[0, 1] of the sound 1=max 0=min, defaults to 1 + :type amplitude: intor float, optional + :param fade: (s) time of fading window rise and decay, defaults to 0.01 + :type fade: float, optional + :param chans: ['mono', 'L', 'R', 'stereo', 'L+TTL', 'TTL+R'] number of + sound channels and type of output, defaults to 'L+TTL' + :type chans: str, optional + :return: streo sound from mono definitions + :rtype: np.ndarray with shape (Nsamples, 2) + """ + sample_rate = rate # Sound card dependent, + tone_duration = duration # sec + fade_duration = fade # sec + chans = chans if isinstance(chans, str) else chans[0] + tvec = np.linspace(0, tone_duration, int(tone_duration * sample_rate)) + tone = amplitude * np.sin(2 * np.pi * frequency * tvec) # tone vec + + len_fade = int(fade_duration * sample_rate) + fade_io = np.hanning(len_fade * 2) + fadein = fade_io[:len_fade] + fadeout = fade_io[len_fade:] + win = np.ones(len(tvec)) + win[:len_fade] = fadein + win[-len_fade:] = fadeout + + tone = tone * win + ttl = np.ones(len(tone)) * 0.99 + one_ms = round(sample_rate / 1000) * 10 + ttl[one_ms:] = 0 + null = np.zeros(len(tone)) + + if frequency == -1: + tone = amplitude * np.random.rand(tone.size) + + if chans == 'mono': + sound = np.array(tone) + elif chans == 'L': + sound = np.array([tone, null]).T + elif chans == 'R': + sound = np.array([null, tone]).T + elif chans == 'stereo': + sound = np.array([tone, tone]).T + elif chans == 'L+TTL': + sound = np.array([tone, ttl]).T + elif chans == 'TTL+R': + sound = np.array([ttl, tone]).T + + return sound
+ + + +
+[docs] +def format_sound(sound, file_path=None, flat=False): + """ + Format sound to send to sound card. + + Binary files to be sent to the sound card need to be a single contiguous + vector of int32 s. 4 Bytes left speaker, 4 Bytes right speaker, ..., etc. + + + :param sound: Stereo sound + :type sound: 2d numpy.array os shape (n_samples, 2) + :param file_path: full path of file. [default: None] + :type file_path: str + """ + bin_sound = (sound * ((2**31) - 1)).astype(np.int32) + + if bin_sound.flags.f_contiguous: + bin_sound = np.ascontiguousarray(bin_sound) + + bin_save = bin_sound.reshape(1, np.multiply(*bin_sound.shape)) + bin_save = np.ascontiguousarray(bin_save) + + if file_path: + with open(file_path, 'wb') as bf: + bf.writelines(bin_save) + bf.flush() + + return bin_sound.flatten() if flat else bin_sound
+ + + +
+[docs] +def configure_sound_card(card=None, sounds=None, indexes=None, sample_rate=96): + if indexes is None: + indexes = [] + if sounds is None: + sounds = [] + if card is None: + card = SoundCardModule() + close_card = True + + if sample_rate in (192, 192000): + sample_rate = SampleRate._192000HZ + elif sample_rate in (96, 96000): + sample_rate = SampleRate._96000HZ + else: + log.error(f'Sound sample rate {sample_rate} should be 96 or 192 (KHz)') + raise (ValueError) + + if len(sounds) != len(indexes): + log.error('Wrong number of sounds and indexes') + raise (ValueError) + + sounds = [format_sound(s, flat=True) for s in sounds] + for sound, index in zip(sounds, indexes, strict=False): + card.send_sound(sound, index, sample_rate, DataType.INT32) + + if close_card: + card.close()
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/tools.html b/_modules/iblrig/tools.html new file mode 100644 index 000000000..a91c8eabb --- /dev/null +++ b/_modules/iblrig/tools.html @@ -0,0 +1,582 @@ + + + + + + iblrig.tools — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.tools

+import asyncio
+import logging
+import os
+import platform
+import re
+import shutil
+import socket
+import subprocess
+from collections.abc import Callable
+from dataclasses import dataclass
+from datetime import date
+from functools import cache
+from pathlib import Path
+from typing import Any, TypeVar
+
+from iblrig import version_management
+from iblrig.constants import BONSAI_EXE, IS_GIT
+from iblrig.path_helper import create_bonsai_layout_from_template, load_pydantic_yaml
+from iblrig.pydantic_definitions import HardwareSettings, RigSettings
+from iblutil.util import get_mac
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +def ask_user(prompt: str, default: bool = False) -> bool: + """ + Prompt the user for a yes/no response. + + This function displays a prompt to the user and expects a yes or no response. + The response is not case-sensitive. If the user presses Enter without + typing anything, the function interprets it as the default response. + + Parameters + ---------- + prompt : str + The prompt message to display to the user. + default : bool, optional + The default response when the user presses Enter without typing + anything. If True, the default response is 'yes' (Y/y or Enter). + If False, the default response is 'no' (N/n or Enter). + + Returns + ------- + bool + True if the user responds with 'yes' + False if the user responds with 'no' + """ + while True: + user_input = input(f'{prompt} [Y/n] ' if default else f'{prompt} [y/N] ').strip().lower() + if not user_input: + return default + elif user_input in ['y', 'yes']: + return True + elif user_input in ['n', 'no']: + return False
+ + + +
+[docs] +def get_anydesk_id(format_id: bool = True, silent: bool = False) -> str | None: + """ + Retrieve the AnyDesk ID of the current machine. + + Parameters + ---------- + format_id : bool, optional + If True (default), format the ID in blocks separated by spaces. + If False, return the ID as one continuous block. + silent : bool, optional + If True, suppresses exceptions and logs them instead. + If False (default), raises exceptions. + + Returns + ------- + str or None + The AnyDesk ID as a formatted string (e.g., '123 456 789') if successful, + or None on failure. + + Raises + ------ + FileNotFoundError + If the AnyDesk executable is not found. + subprocess.CalledProcessError + If an error occurs while executing the AnyDesk command. + StopIteration + If the subprocess output is empty. + UnicodeDecodeError + If there is an issue decoding the subprocess output. + + Notes + ----- + The function attempts to find the AnyDesk executable and retrieve the ID using the command line. + On success, the AnyDesk ID is returned as a formatted string. If silent is True, exceptions are logged, + and None is returned on failure. If silent is False, exceptions are raised on failure. + """ + anydesk_id = None + try: + if cmd := shutil.which('anydesk'): + pass + elif os.name == 'nt': + cmd = str(Path(os.environ['PROGRAMFILES(X86)'], 'AnyDesk', 'anydesk.exe')) + if cmd is None or not Path(cmd).exists(): + raise FileNotFoundError('AnyDesk executable not found') + + proc = subprocess.Popen([cmd, '--get-id'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + if proc.stdout and re.match(r'^\d{10}$', id_string := next(proc.stdout).decode()): + anydesk_id = f'{int(id_string):,}'.replace(',', ' ' if format_id else '') + except (FileNotFoundError, subprocess.CalledProcessError, StopIteration, UnicodeDecodeError) as e: + if silent: + log.debug(e, exc_info=True) + else: + raise e + return anydesk_id
+ + + +
+[docs] +def static_vars(**kwargs) -> Callable[..., Any]: + """ + Decorator to add static variables to a function. + + This decorator allows you to add static variables to a function by providing + keyword arguments. Static variables are shared across all calls to the + decorated function. + + Parameters + ---------- + **kwargs + Keyword arguments where the keys are variable names and the values are + the initial values of the static variables. + + Returns + ------- + function + A decorated function with the specified static variables. + """ + + def decorate(func: Callable[..., Any]) -> Callable[..., Any]: + for k in kwargs: + setattr(func, k, kwargs[k]) + return func + + return decorate
+ + + +
+[docs] +@static_vars(return_value=None) +def internet_available(host: str = '8.8.8.8', port: int = 53, timeout: int = 3, force_update: bool = False) -> bool: + """ + Check if the internet connection is available. + + This function checks if an internet connection is available by attempting to + establish a connection to a specified host and port. It will use a cached + result if the latter is available and `force_update` is set to False. + + Parameters + ---------- + host : str, optional + The IP address or domain name of the host to check the connection to. + Default is "8.8.8.8" (Google's DNS server). + port : int, optional + The port to use for the connection check. Default is 53 (DNS port). + timeout : int, optional + The maximum time (in seconds) to wait for the connection attempt. + Default is 3 seconds. + force_update : bool, optional + If True, force an update and recheck the internet connection even if + the result is cached. Default is False. + + Returns + ------- + bool + True if an internet connection is available, False otherwise. + """ + if not force_update and internet_available.return_value: + return internet_available.return_value + try: + socket.setdefaulttimeout(timeout) + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect((host, port)) + internet_available.return_value = True + except OSError: + internet_available.return_value = False + return internet_available.return_value
+ + + +
+[docs] +def alyx_reachable() -> bool: + """ + Check if Alyx can be connected to. + + Returns + ------- + bool + True if Alyx can be connected to, False otherwise. + """ + settings: RigSettings = load_pydantic_yaml(RigSettings) + if settings.ALYX_URL is not None: + return internet_available(host=settings.ALYX_URL.host, port=443, timeout=1, force_update=True) + return False
+ + + +def _build_bonsai_cmd( + workflow_file: str | Path, + parameters: dict[str, Any] | None = None, + start: bool = True, + debug: bool = False, + bootstrap: bool = True, + editor: bool = True, +) -> list[str]: + """ + Execute a Bonsai workflow within a subprocess call. + + Parameters + ---------- + workflow_file : str | Path + Path to the Bonsai workflow file. + parameters : dict[str, str], optional + Parameters to be passed to Bonsai workflow. + start : bool, optional + Start execution of the workflow within Bonsai (default is True). + debug : bool, optional + Enable debugging mode if True (default is False). + Only applies if editor is True. + bootstrap : bool, optional + Enable Bonsai bootstrapping if True (default is True). + editor : bool, optional + Enable Bonsai editor if True (default is True). + + Returns + ------- + list of str + The Bonsai command to pass to subprocess. + + Raises + ------ + FileNotFoundError + If the Bonsai executable does not exist. + If the specified workflow file does not exist. + """ + if not BONSAI_EXE.exists(): + raise FileNotFoundError(BONSAI_EXE) + workflow_file = Path(workflow_file) + if not workflow_file.exists(): + raise FileNotFoundError(workflow_file) + create_bonsai_layout_from_template(workflow_file) + + cmd = [str(BONSAI_EXE), str(workflow_file)] + if start: + cmd.append('--start' if debug else '--start-no-debug') + if not editor: + cmd.append('--no-editor') + if not bootstrap: + cmd.append('--no-boot') + if parameters is not None: + for key, value in parameters.items(): + cmd.append(f'-p:{key}={str(value)}') + return cmd + + +
+[docs] +def call_bonsai( + workflow_file: str | Path, + parameters: dict[str, Any] | None = None, + start: bool = True, + debug: bool = False, + bootstrap: bool = True, + editor: bool = True, + wait: bool = True, + check: bool = False, +) -> subprocess.Popen[bytes] | subprocess.Popen[str | bytes | Any] | subprocess.CompletedProcess: + """ + Execute a Bonsai workflow within a subprocess call. + + Parameters + ---------- + workflow_file : str | Path + Path to the Bonsai workflow file. + parameters : dict[str, str], optional + Parameters to be passed to Bonsai workflow. + start : bool, optional + Start execution of the workflow within Bonsai (default is True). + debug : bool, optional + Enable debugging mode if True (default is False). + Only applies if editor is True. + bootstrap : bool, optional + Enable Bonsai bootstrapping if True (default is True). + editor : bool, optional + Enable Bonsai editor if True (default is True). + wait : bool, optional + Wait for Bonsai process to finish (default is True). + check : bool, optional + Raise CalledProcessError if Bonsai process exits with non-zero exit code (default is False). + Only applies if wait is True. + + Returns + ------- + Popen[bytes] | Popen[str | bytes | Any] | CompletedProcess + Pointer to the Bonsai subprocess if wait is False, otherwise subprocess.CompletedProcess. + + Raises + ------ + FileNotFoundError + If the Bonsai executable does not exist. + If the specified workflow file does not exist. + + """ + cmd = _build_bonsai_cmd(workflow_file, parameters, start, debug, bootstrap, editor) + cwd = Path(workflow_file).parent + log.info(f'Starting Bonsai workflow `{workflow_file.name}`') + log.debug(' '.join(map(str, cmd))) + if wait: + return subprocess.run(args=cmd, cwd=cwd, check=check) + else: + return subprocess.Popen(args=cmd, cwd=cwd)
+ + + +
+[docs] +async def call_bonsai_async( + workflow_file: str | Path, + parameters: dict[str, Any] | None = None, + start: bool = True, + debug: bool = False, + bootstrap: bool = True, + editor: bool = True, +) -> asyncio.subprocess.Process: + """ + Asynchronously execute a Bonsai workflow within a subprocess call. + + Parameters + ---------- + workflow_file : str | Path + Path to the Bonsai workflow file. + parameters : dict[str, str], optional + Parameters to be passed to Bonsai workflow. + start : bool, optional + Start execution of the workflow within Bonsai (default is True). + debug : bool, optional + Enable debugging mode if True (default is False). + Only applies if editor is True. + bootstrap : bool, optional + Enable Bonsai bootstrapping if True (default is True). + editor : bool, optional + Enable Bonsai editor if True (default is True). + + Returns + ------- + asyncio.subprocess.Process + Pointer to the Bonsai subprocess if wait is False, otherwise subprocess.CompletedProcess. + + Raises + ------ + FileNotFoundError + If the Bonsai executable does not exist. + If the specified workflow file does not exist. + + """ + program, *cmd = _build_bonsai_cmd(workflow_file, parameters, start, debug, bootstrap, editor) + log.info(f'Starting Bonsai workflow `{workflow_file.name}`') + log.debug(' '.join(map(str, cmd))) + working_dir = Path(workflow_file).parent + return await asyncio.create_subprocess_exec( + program, *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=working_dir + )
+ + + +T = TypeVar('T', bound=object) + + +
+[docs] +def get_inheritors(cls: T) -> set[T]: + """Obtain a set of all direct inheritors of a class.""" + subclasses = set(cls.__subclasses__()) + for child in subclasses: + subclasses = subclasses.union(get_inheritors(child)) + return subclasses
+ + + +
+[docs] +@dataclass +class ANSI: + """ANSI Codes for formatting text on the CLI.""" + + WHITE = '\033[37m' + PURPLE = '\033[95m' + CYAN = '\033[96m' + DARKCYAN = '\033[36m' + BLUE = '\033[94m' + GREEN = '\033[92m' + YELLOW = '\033[93m' + RED = '\033[91m' + BOLD = '\033[1m' + DIM = '\033[2m' + UNDERLINE = '\033[4m' + END = '\033[0m'
+ + + +cached_check_output = cache(subprocess.check_output) + + +
+[docs] +def get_lab_location_dict(hardware_settings: HardwareSettings, iblrig_settings: RigSettings) -> dict[str, Any]: + lab_location = dict() + lab_location['rig_name'] = hardware_settings.RIG_NAME + lab_location['iblrig_version'] = str(version_management.get_local_version()) + lab_location['last_seen'] = date.today().isoformat() + + machine = dict() + machine['platform'] = platform.platform() + machine['hostname'] = socket.gethostname() + machine['fqdn'] = socket.getfqdn() + machine['ip'] = socket.gethostbyname(machine['hostname']) + machine['mac'] = get_mac() + machine['anydesk'] = get_anydesk_id(format_id=False, silent=True) + lab_location['machine'] = machine + + git = dict() + git['is_git'] = IS_GIT + git['branch'] = version_management.get_branch() + git['commit_id'] = version_management.get_commit_hash() + git['is_dirty'] = version_management.is_dirty() + lab_location['git'] = git + + # TODO: add hardware/firmware versions of bpod, soundcard, rotary encoder, frame2ttl, ambient module, etc + # TODO: add validation errors/warnings + + return lab_location
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/transfer_experiments.html b/_modules/iblrig/transfer_experiments.html new file mode 100644 index 000000000..32f7be6ee --- /dev/null +++ b/_modules/iblrig/transfer_experiments.html @@ -0,0 +1,774 @@ + + + + + + iblrig.transfer_experiments — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.transfer_experiments

+import datetime
+import json
+import logging
+import os
+import shutil
+import socket
+import traceback
+import uuid
+from enum import IntEnum
+from os.path import samestat
+from pathlib import Path
+
+import ibllib.pipes.misc
+import iblrig
+import one.alf.files as alfiles
+from ibllib.io import raw_data_loaders, session_params
+from ibllib.pipes.misc import sleepless
+from iblrig.raw_data_loaders import load_task_jsonable
+from iblutil.io import hashfile
+from one.util import ensure_list
+
+log = logging.getLogger(__name__)
+
+ES_CONTINUOUS = 0x80000000
+ES_SYSTEM_REQUIRED = 0x00000001
+
+
+
+[docs] +class CopyState(IntEnum): + HARD_RESET = -1 + NOT_REGISTERED = 0 + PENDING = 1 + COMPLETE = 2 + FINALIZED = 3
+ + + +@sleepless +def _copy2_checksum(src: str, dst: str, *args, **kwargs) -> str: + """ + Copy a file from source to destination with checksum verification. + + This function copies a file from the source path to the destination path + while verifying the BLAKE2B hash of the source and destination files. If the + BLAKE2B hashes do not match after copying, an OSError is raised. + + Parameters + ---------- + src : str + The path to the source file. + dst : str + The path to the destination file. + *args, **kwargs + Additional arguments and keyword arguments to pass to `shutil.copy2`. + + Returns + ------- + str + The path to the copied file. + + Raises + ------ + OSError + If the BLAKE2B hashes of the source and destination files do not match. + """ + log.info(f'Processing `{src}`:') + log.info(' - calculating hash of local file') + src_md5 = hashfile.blake2b(src, False) + if os.path.exists(dst) and samestat(os.stat(src), os.stat(dst)): + log.info(' - file already exists at destination') + log.info(' - calculating hash of remote file') + if src_md5 == hashfile.blake2b(dst, False): + log.info(' - local and remote BLAKE2B hashes match, skipping copy') + return dst + else: + log.info(' - local and remote hashes DO NOT match') + log.info(f' - copying file to `{dst}`') + return_val = shutil.copy2(src, dst, *args, **kwargs) + log.info(' - calculating hash of remote file') + if not src_md5 == hashfile.blake2b(dst, False): + raise OSError(f'Error copying {src}: hash mismatch.') + log.info(' - local and remote hashes match, copy successful') + return return_val + + +
+[docs] +def copy_folders(local_folder: Path, remote_folder: Path, overwrite: bool = False) -> bool: + """ + Copy folders and files from a local location to a remote location. + + This function copies all folders and files from a local directory to a + remote directory. It provides options to overwrite existing files in + the remote directory and ignore specific file patterns. + + Parameters + ---------- + local_folder : Path + The path to the local folder to copy from. + remote_folder : Path + The path to the remote folder to copy to. + overwrite : bool, optional + If True, overwrite existing files in the remote folder. Default is False. + + Returns + ------- + bool + True if the copying is successful, False otherwise. + """ + status = True + try: + remote_folder.parent.mkdir(parents=True, exist_ok=True) + shutil.copytree( + local_folder, + remote_folder, + dirs_exist_ok=overwrite, + ignore=shutil.ignore_patterns('transfer_me.flag'), + copy_function=_copy2_checksum, + ) + except OSError: + log.error(traceback.format_exc()) + log.info(f'Could not copy {local_folder} to {remote_folder}') + status = False + return status
+ + + +
+[docs] +class SessionCopier: + """Initialize and copy session data to a remote server.""" + + assert_connect_on_init = True + """bool: Raise error if unable to write stub file to remote server.""" + + _experiment_description = None + """dict: The experiment description file used for the copy.""" + + tag = f'{socket.gethostname()}_{uuid.getnode()}' + """str: The device name (adds this to the experiment description stub file on the remote server).""" + +
+[docs] + def __init__(self, session_path, remote_subjects_folder=None, tag=None): + """ + Initialize and copy session data to a remote server. + + Parameters + ---------- + session_path : str, pathlib.Path + The partial or session path to copy. + remote_subjects_folder : str, pathlib.Path + The remote server path to which to copy the session data. + tag : str + The device name (adds this to the experiment description stub file on the remote server). + """ + self.tag = tag or self.tag + self.session_path = Path(session_path) + self.remote_subjects_folder = Path(remote_subjects_folder) if remote_subjects_folder else None
+ + + def __repr__(self): + return f'{super().__repr__()} \n local: {self.session_path} \n remote: {self.remote_session_path}' + + @property + def state(self): + return self.get_state()[0] + +
+[docs] + def run(self, number_of_expected_devices=None): + """ + Run the copy of this device experiment. + + Will try to get as far as possible in the copy process (from states 0 init experiment to state 3 finalize experiment) + if possible, and return earlier if the process can't be completed. + """ + if self.state == CopyState.HARD_RESET: # this case is not implemented automatically and corresponds to a hard reset + log.info(f'{self.state}, {self.session_path}') + shutil.rmtree(self.remote_session_path) + self.initialize_experiment() + if self.state == CopyState.NOT_REGISTERED: # the session hasn't even been initialized: copy the stub to the remote + log.info(f'{self.state}, {self.session_path}') + self.initialize_experiment() + if self.state == CopyState.PENDING: # the session is ready for copy + log.info(f'{self.state}, {self.session_path}') + self.copy_collections() + if self.state == CopyState.COMPLETE: + log.info(f'{self.state}, {self.session_path}') + self.finalize_copy(number_of_expected_devices=number_of_expected_devices) + if self.state == CopyState.FINALIZED: + log.info(f'{self.state}, {self.session_path}')
+ + +
+[docs] + def get_state(self) -> tuple[CopyState | None, str]: + """ + Gets the current copier state. + + State 0: this device experiment has not been initialized for this device + State 1: this device experiment is initialized (the experiment description stub is present on the remote) + State 2: this device experiment is copied on the remote server, but other devices copies are still pending + State 3: the whole experiment is finalized and all data is on the server + :return: + """ + if self.remote_subjects_folder is None or not self.remote_subjects_folder.exists(): + return None, f'Remote subjects folder {self.remote_subjects_folder} set to Null or unreachable' + if not self.file_remote_experiment_description.exists(): + return ( + CopyState.NOT_REGISTERED, + f'Copy object not registered on server: {self.file_remote_experiment_description} does not exist', + ) + status_file = self.glob_file_remote_copy_status() + if status_file is None: + status_file = self.file_remote_experiment_description.with_suffix('.status_pending') + status_file.touch() + log.warning(f'{status_file} not found and created') + if status_file.name.endswith('pending'): + return CopyState.PENDING, f'Copy pending {self.file_remote_experiment_description}' + elif status_file.name.endswith('complete'): + return CopyState.COMPLETE, f'Copy complete {self.file_remote_experiment_description}' + elif status_file.name.endswith('final'): + return CopyState.FINALIZED, f'Copy finalized {self.file_remote_experiment_description}'
+ + + @property + def experiment_description(self): + return self._experiment_description + + @property + def remote_session_path(self): + if self.remote_subjects_folder: + # padded_sequence ensures session path has zero padded number folder, e.g. 1 -> 001 + session_parts = alfiles.padded_sequence(self.session_path).parts[-3:] + return self.remote_subjects_folder.joinpath(*session_parts) + + @property + def file_experiment_description(self): + """Returns the local experiment description file, if none found, returns one with the tag.""" + return next( + self.session_path.glob('_ibl_experiment.description*'), + self.session_path.joinpath(f'_ibl_experiment.description_{self.tag}.yaml'), + ) + +
+[docs] + def glob_file_remote_copy_status(self, status='*'): + """status: pending / complete""" + fr = self.file_remote_experiment_description + return next(fr.parent.glob(f'{fr.stem}.status_{status}'), None) if fr else None
+ + + @property + def file_remote_experiment_description(self): + """Return the remote path to the remote stub file.""" + if self.remote_subjects_folder: + return session_params.get_remote_stub_name(self.remote_session_path, device_id=self.tag) + + @property + def remote_experiment_description_stub(self): + return session_params.read_params(self.file_remote_experiment_description) + + def _copy_collections(self): + """ + Copy collections defined in experiment description file. + + This is the method to subclass for pre- and post- copy routines. + + Returns + ------- + bool + True if transfer successfully completed. + """ + status = True + exp_pars = session_params.read_params(self.session_path) + collections = set() + # First glob on each collection pattern to find all folders to transfer + for collection in session_params.get_collections(exp_pars, flat=True): + folders = filter(Path.is_dir, self.session_path.glob(collection)) + _collections = list(map(lambda x: x.relative_to(self.session_path).as_posix(), folders)) + if not _collections: + log.error(f'No collection(s) matching "{collection}" found') + status = False + continue + collections.update(_collections) + + # Attempt to copy each folder + for collection in collections: + local_collection = self.session_path.joinpath(collection) + assert local_collection.exists(), f'local collection "{collection}" no longer exists' + log.info(f'transferring {self.session_path} - {collection}') + remote_collection = self.remote_session_path.joinpath(collection) + if remote_collection.exists(): + # this is far from ideal: we currently recopy all files even if some already copied + log.warning(f'Collection {remote_collection} already exists, removing') + shutil.rmtree(remote_collection) + status &= copy_folders(local_collection, remote_collection) + status &= self.copy_snapshots() # special case: copy snapshots without deleting or overwriting remote files + return status + +
+[docs] + def copy_snapshots(self): + """ + Copy snapshots files from root session path. + + Unlike the collection folders defined in the experiment description folder, the snapshots folder is optional and + may exist on multiple acquisition PCs. This method will copy any files over if the snapshots folder exists, + however it will fail if a file of the same name already exists. This ensures snapshots from multiple computers + don't get overwritten. + + Returns + ------- + bool + True if transfer successfully completed. + """ + snapshots = self.session_path.joinpath('snapshots') + if not snapshots.exists(): + log.debug('Snapshots folder %s does not exist', snapshots.as_posix()) + return True + log.info(f'transferring {self.session_path} - {snapshots.name}') + remote_snapshots = self.remote_session_path.joinpath(snapshots.name) + # Get set of local and remote snapshot filenames + local_files, remote_files = ( + set(map(lambda x: x.relative_to(p).as_posix(), filter(Path.is_file, p.rglob('*')))) + for p in (snapshots, remote_snapshots) + ) + if not any(local_files): + log.debug('Snapshots folder %s is empty', snapshots.as_posix()) + return True + if any(duplicates := local_files.intersection(remote_files)): + log.error('The following snapshots already exist in %s\n%s', remote_snapshots.as_posix(), ', '.join(duplicates)) + log.info('Could not copy %s to %s', snapshots.as_posix(), remote_snapshots.as_posix()) + return False + # 'overwrite' actually means 'don't raise if remote folder exists'. + # We've already checked that filenames don't conflict. + return copy_folders(snapshots, remote_snapshots, overwrite=True)
+ + +
+[docs] + def copy_collections(self): + """ + Recursively copies the collection folders into the remote session path. + + Do not overload, overload _copy_collections instead. + """ + if self.glob_file_remote_copy_status('complete'): + log.warning( + f'Copy already complete for {self.session_path},' + f' remove {self.glob_file_remote_copy_status("complete")} to force' + ) + return True + status = self._copy_collections() + # post copy stuff: rename the pending flag to complete + if status: + pending_file = self.glob_file_remote_copy_status('pending') + pending_file.rename(pending_file.with_suffix('.status_complete')) + if self.session_path.joinpath('transfer_me.flag').exists(): + self.session_path.joinpath('transfer_me.flag').unlink() + return status
+ + +
+[docs] + def initialize_experiment(self, acquisition_description=None, overwrite=True): + """ + Copy acquisition description yaml to the server and local transfers folder. + + Parameters + ---------- + acquisition_description : dict + The data to write to the experiment.description.yaml file. + overwrite : bool + If true, overwrite any existing file with the new one, otherwise, update the existing file. + """ + if acquisition_description is None: + acquisition_description = self.experiment_description + + assert acquisition_description + + # First attempt to add the remote description stub to the _device folder on the remote session + if not self.remote_subjects_folder: + log.info('The remote path is unspecified and remote experiment.description stub creation is omitted.') + else: + remote_stub_file = self.file_remote_experiment_description + previous_description = ( + session_params.read_params(remote_stub_file) if remote_stub_file.exists() and not overwrite else {} + ) + try: + merged_description = session_params.merge_params(previous_description, acquisition_description) + session_params.write_yaml(remote_stub_file, merged_description) + for f in remote_stub_file.parent.glob(remote_stub_file.stem + '.status_*'): + f.unlink() + remote_stub_file.with_suffix('.status_pending').touch() + log.info(f'Written data to remote device at: {remote_stub_file}.') + except Exception as e: + if self.assert_connect_on_init: + raise RuntimeError(f'Failed to write data to remote device at: {remote_stub_file}. \n {e}') from e + log.warning(f'Failed to write data to remote device at: {remote_stub_file}. \n {e}') + + # then create on the local machine + previous_description = ( + session_params.read_params(self.file_experiment_description) + if self.file_experiment_description.exists() and not overwrite + else {} + ) + session_params.write_yaml( + self.file_experiment_description, session_params.merge_params(previous_description, acquisition_description) + ) + log.info(f'Written data to local session at : {self.file_experiment_description}.')
+ + +
+[docs] + def finalize_copy(self, number_of_expected_devices=None): + """At the end of the copy, check if all the files are there and if so, aggregate the device files.""" + ready_to_finalize = 0 + # List the stub files in _devices folder + files_stub = list(self.file_remote_experiment_description.parent.glob('*.yaml')) + if number_of_expected_devices is None: + number_of_expected_devices = len(files_stub) + log.debug(f'Number of expected devices is {number_of_expected_devices}') + + for file_stub in files_stub: + ready_to_finalize += int(file_stub.with_suffix('.status_complete').exists()) + ad_stub = session_params.read_params(file_stub) + # here we check the sync field of the device files + if next(iter(ad_stub.get('sync', {})), None) != 'bpod' and number_of_expected_devices == 1: + log.warning( + 'Only bpod is supported for single device sessions, it seems you are ' + 'attempting to transfer a session with more than one device.' + ) + return + + if ready_to_finalize > number_of_expected_devices: + log.error('More stub files (%i) than expected devices (%i)', ready_to_finalize, number_of_expected_devices) + return + log.info(f'{ready_to_finalize}/{number_of_expected_devices} copy completion status') + if ready_to_finalize == number_of_expected_devices: + for file_stub in files_stub: + session_params.aggregate_device(file_stub, self.remote_session_path.joinpath('_ibl_experiment.description.yaml')) + file_stub.with_suffix('.status_complete').rename(file_stub.with_suffix('.status_final')) + self.remote_session_path.joinpath('raw_session.flag').touch()
+
+ + + +
+[docs] +class VideoCopier(SessionCopier): + tag = 'video' + assert_connect_on_init = True + +
+[docs] + def create_video_stub(self, config, collection='raw_video_data'): + acquisition_description = self.config2stub(config, collection) + session_params.write_params(self.session_path, acquisition_description)
+ + +
+[docs] + @staticmethod + def config2stub(config: dict, collection: str = 'raw_video_data') -> dict: + """ + Generate acquisition description stub from a camera config dict. + + Parameters + ---------- + config : dict + A cameras configuration dictionary, found in `device_cameras` of hardware_settings.yaml. + collection : str + The video output collection. + + Returns + ------- + dict + An acquisition description file stub. + """ + cameras = {} + for label, settings in filter(lambda itms: itms[0] != 'BONSAI_WORKFLOW', config.items()): + settings_mod = {k.lower(): v for k, v in settings.items() if v is not None and k != 'INDEX'} + cameras[label] = dict(collection=collection, **settings_mod) + acq_desc = {'devices': {'cameras': cameras}, 'version': '1.0.0'} + return acq_desc
+ + +
+[docs] + def initialize_experiment(self, acquisition_description=None, **kwargs): + if not acquisition_description: + # creates the acquisition description stub if not found, and then read it + if not self.file_experiment_description.exists(): + raise FileNotFoundError(self.file_experiment_description) + acquisition_description = session_params.read_params(self.file_experiment_description) + self._experiment_description = acquisition_description + super().initialize_experiment(acquisition_description=acquisition_description, **kwargs)
+
+ + + +
+[docs] +class BehaviorCopier(SessionCopier): + tag = 'behavior' + assert_connect_on_init = False + + @property + def experiment_description(self): + return session_params.read_params(self.session_path) + + def _copy_collections(self): + """Patch settings files before copy. + + Before copying the collections, this method checks that the behaviour data are valid. The + following checks are made: + + #. Check at least 1 task collection in experiment description. If not, return. + #. For each collection, check for task settings. If any are missing, return. + #. If SESSION_END_TIME is missing, assumes task crashed. If so and task data missing and + not a chained protocol (i.e. it is the only task collection), assume a dud and remove + the remote stub file. Otherwise, patch settings with total trials, end time, etc. + + Returns + ------- + bool + True if transfer successfully completed. + + """ + collections = session_params.get_task_collection(self.experiment_description) + if not collections: + log.error(f'Skipping: no task collections defined for {self.session_path}') + return False + for collection in (collections := ensure_list(collections)): + task_settings = raw_data_loaders.load_settings(self.session_path, task_collection=collection) + if task_settings is None: + log.info(f'Skipping: no task settings found for {self.session_path}') + return False # may also want to remove session here if empty + # here if the session end time has not been labeled we assume that the session crashed, and patch the settings + if task_settings['SESSION_END_TIME'] is None: + jsonable = self.session_path.joinpath(collection, '_iblrig_taskData.raw.jsonable') + if not jsonable.exists(): + log.info(f'Skipping: no task data found for {self.session_path}') + # No local data and only behaviour stub in remote; assume dud and remove entire session + if ( + self.remote_session_path.exists() + and len(collections) == 1 + and len(list(self.file_remote_experiment_description.parent.glob('*.yaml'))) <= 1 + ): + shutil.rmtree(self.remote_session_path) # remove likely dud + return False + trials, bpod_data = load_task_jsonable(jsonable) + ntrials = trials.shape[0] + # We have the case where the session hard crashed. + # Patch the settings file to wrap the session and continue the copying. + log.warning(f'Recovering crashed session {self.session_path}') + settings_file = self.session_path.joinpath(collection, '_iblrig_taskSettings.raw.json') + with open(settings_file) as fid: + raw_settings = json.load(fid) + raw_settings['NTRIALS'] = int(ntrials) + raw_settings['NTRIALS_CORRECT'] = int(trials['trial_correct'].sum()) + raw_settings['TOTAL_WATER_DELIVERED'] = int(trials['reward_amount'].sum()) + # cast the timestamp in a datetime object and add the session length to it + end_time = datetime.datetime.strptime(raw_settings['SESSION_START_TIME'], '%Y-%m-%dT%H:%M:%S.%f') + end_time += datetime.timedelta(seconds=bpod_data[-1]['Trial end timestamp']) + raw_settings['SESSION_END_TIME'] = end_time.strftime('%Y-%m-%dT%H:%M:%S.%f') + with open(settings_file, 'w') as fid: + json.dump(raw_settings, fid) + log.critical(f'{self.state}, {self.session_path}') + return super()._copy_collections() # proceed with copy + +
+[docs] + def finalize_copy(self, number_of_expected_devices=None): + """If main sync is bpod, expect a single stub file.""" + if number_of_expected_devices is None and session_params.get_sync(self.remote_experiment_description_stub) == 'bpod': + number_of_expected_devices = 1 + super().finalize_copy(number_of_expected_devices=number_of_expected_devices)
+
+ + + +
+[docs] +class EphysCopier(SessionCopier): + tag = 'ephys' + assert_connect_on_init = True + +
+[docs] + def initialize_experiment(self, acquisition_description=None, nprobes=None, main_sync=True, **kwargs): + if not acquisition_description: + acquisition_description = {'devices': {'neuropixel': {}}} + neuropixel = acquisition_description['devices']['neuropixel'] + if nprobes is None: + nprobes = len(list(self.session_path.glob('**/*.ap.bin'))) + for n in range(nprobes): + name = f'probe{n:02}' + neuropixel[name] = {'collection': f'raw_ephys_data/{name}', 'sync_label': 'imec_sync'} + sync_file = Path(iblrig.__file__).parent.joinpath('device_descriptions', 'sync', 'nidq.yaml') + acquisition_description = acquisition_description if neuropixel else {} + if main_sync: + acquisition_description.update(session_params.read_params(sync_file)) + + self._experiment_description = acquisition_description + super().initialize_experiment(acquisition_description=acquisition_description, **kwargs) + # once the session folders have been initialized, create the probe folders + for n in range(nprobes): + self.session_path.joinpath('raw_ephys_data', f'probe{n:02}').mkdir(exist_ok=True, parents=True)
+ + + def _copy_collections(self): + """Here we overload the copy to be able to rename the probes properly and also create the insertions.""" + log.info(f'Transferring ephys session: {self.session_path} to {self.remote_session_path}') + ibllib.pipes.misc.rename_ephys_files(self.session_path) + ibllib.pipes.misc.move_ephys_files(self.session_path) + # copy the wiring files from template + path_wiring = Path(iblrig.__file__).parent.joinpath('device_descriptions', 'neuropixel', 'wirings') + probe_model = '3A' + for file_nidq_bin in self.session_path.joinpath('raw_ephys_data').glob('*.nidq.bin'): + probe_model = '3B' + shutil.copy(path_wiring.joinpath('nidq.wiring.json'), file_nidq_bin.with_suffix('.wiring.json')) + for file_ap_bin in self.session_path.joinpath('raw_ephys_data').rglob('*.ap.bin'): + shutil.copy(path_wiring.joinpath(f'{probe_model}.wiring.json'), file_ap_bin.with_suffix('.wiring.json')) + try: + ibllib.pipes.misc.create_alyx_probe_insertions(self.session_path) + except Exception: + log.error(traceback.print_exc()) + log.info('Probe creation failed, please create the probe insertions manually. Continuing transfer...') + return copy_folders( + local_folder=self.session_path.joinpath('raw_ephys_data'), + remote_folder=self.remote_session_path.joinpath('raw_ephys_data'), + overwrite=True, + )
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/upgrade_iblrig.html b/_modules/iblrig/upgrade_iblrig.html new file mode 100644 index 000000000..09b3a5848 --- /dev/null +++ b/_modules/iblrig/upgrade_iblrig.html @@ -0,0 +1,286 @@ + + + + + + iblrig.upgrade_iblrig — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.upgrade_iblrig

+# WARNING: CHANGES TO THIS FILE WILL DIRECTLY IMPACT THE USER'S ABILITY TO
+# AUTOMATICALLY UPGRADE THE SYSTEM. MODIFY WITH EXTREME CAUTION AND ONLY IF
+# ABSOLUTELY NECESSARY.
+import sys
+from subprocess import CalledProcessError, SubprocessError, run
+
+import colorlog
+
+from iblrig.constants import BASE_DIR
+from iblrig.tools import ask_user
+from iblrig.version_management import check_upgrade_prerequisites, get_local_version, get_remote_version, is_dirty
+
+handler = colorlog.StreamHandler()
+handler.setFormatter(colorlog.ColoredFormatter('%(log_color)s%(message)s'))
+
+log = colorlog.getLogger(__name__)
+log.setLevel(colorlog.INFO)
+log.addHandler(handler)
+
+
+def _exit_or_raise(message: str | Exception, raise_exception: bool = True, return_code: int | None = None):
+    """
+    Handle errors by either raising an exception or logging an error message and
+    exiting the program.
+
+    Parameters
+    ----------
+    message : str or Exception
+        The error message or an Exception to be handled.
+    raise_exception : bool, optional
+        If True, raise the provided Exception or a new Exception with the
+        provided error message. If False, log the error message and exit the
+        program. Defaults to True.
+    return_code : int or None, optional
+        The exit code to be used with sys.exit() if raise_exception is False.
+        If None, attempt to extract the return code from the provided Exception
+        (if it's a CalledProcessError), defaulting to 1 if no return code is
+        found.
+
+    Raises
+    ------
+    Exception
+        If raise_exception is True, raise the provided Exception or a new
+        Exception with the provided error message.
+
+    Exits
+    -----
+    sys.exit(return_code)
+        If raise_exception is False, log the error message, and exit the program
+        with the specified return code.
+    """
+    if raise_exception:
+        raise message if isinstance(message, Exception) else Exception(message)
+    else:
+        if return_code is None:
+            return_code = message.returncode if isinstance(message, CalledProcessError) else 1
+        if isinstance(message, Exception):
+            message = str(message)
+        log.error(f'{message}')
+        sys.exit(return_code)
+
+
+
+[docs] +def call_subprocesses(reset_repo: bool = False, **kwargs) -> None: + """ + Perform upgrade-related subprocess calls. + + Parameters + ---------- + reset_repo : bool, optional + If True, reset the local Git repository to its remote state before + upgrading. + **kwargs + Additional keyword arguments to be passed to subprocess calls. + + Returns + ------- + None + This function does not return any value. + + Raises + ------ + subprocess.CalledProcessError + If any subprocess calls result in a non-zero return code. + FileNotFoundError + If any of the subprocess commands executable is not found. + """ + calls = [ + ['git', 'pull', '--tags'], + [sys.executable, '-m', 'pip', 'install', '-U', 'pip'], + [sys.executable, '-m', 'pip', 'install', '-U', '-e', BASE_DIR], + ] + if reset_repo: + calls.insert(0, ['git', 'reset', '--hard']) + for call in calls: + log.warning('\n' + ' '.join(call)) + run(call, cwd=BASE_DIR, check=True, **kwargs)
+ + + +
+[docs] +def upgrade(raise_exceptions: bool = False, allow_reset: bool = False): + """ + Upgrade the IBLRIG software installation. + + This function upgrades the IBLRIG software installation to the latest + version available in the Git repository. It checks the local and remote + versions, confirms the upgrade with the user if necessary, and performs the + upgrade. + """ + # check some basics + check_upgrade_prerequisites(exception_handler=_exit_or_raise, raise_exception=raise_exceptions) + + # get local and remote version + if (v_local := get_local_version()) is None: + _exit_or_raise('Could not obtain local version of IBLRIG.', raise_exception=raise_exceptions) + if (v_remote := get_remote_version()) is None: + _exit_or_raise('Could not obtain remote version of IBLRIG.', raise_exception=raise_exceptions) + print(f'Local version: {v_local}') + print(f'Remote version: {v_remote}') + if v_local >= v_remote and not ask_user('\nNo need to upgrade. Do you want to run the upgrade routine anyways?', False): + sys.exit(0) + + # check dirty state + if reset_repo := is_dirty(): + print('\nThere are local changes in your copy of IBLRIG that will be lost when upgrading.') + if not ask_user('Do you want to proceed?', False): + sys.exit(0) + + # call subprocesses and report outcome + try: + call_subprocesses(reset_repo=reset_repo) + except (FileNotFoundError, SubprocessError, Exception) as e: + if raise_exceptions: + raise e + else: + log.exception(e) + log.error( + f'\nAutomatic Upgrade of IBLRIG was NOT successful.\n' + f'Please run the following commands for a manual upgrade:\n\n' + f' git pull --tags {BASE_DIR}\n' + f' pip install -U -e {BASE_DIR}\n' + ) + sys.exit(e.returncode if isinstance(e, CalledProcessError) else 1) + else: + log.info(f'\nUpgrade to IBLRIG {v_remote} was successful.\n') + sys.exit(0)
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/valve.html b/_modules/iblrig/valve.html new file mode 100644 index 000000000..94602c296 --- /dev/null +++ b/_modules/iblrig/valve.html @@ -0,0 +1,278 @@ + + + + + + iblrig.valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.valve

+import datetime
+import warnings
+from collections.abc import Iterable, Sequence
+
+import numpy as np
+import scipy
+from numpy.polynomial import Polynomial
+from pydantic import NonNegativeFloat, PositiveFloat, validate_call
+
+from iblrig.pydantic_definitions import HardwareSettingsValve
+
+
+
+[docs] +class ValveValues: + _dtype = [('open_times_ms', float), ('weights_g', float)] + _data: np.ndarray + _polynomial: Polynomial + +
+[docs] + def __init__(self, open_times_ms: Sequence[float], weights_g: Sequence[float]): + self.clear_data() + self.add_samples(open_times_ms, weights_g)
+ + + @staticmethod + def _fcn(x: np.ndarray, a: float, b: float, c: float) -> np.ndarray: + return a + b * x + c * np.square(x) + +
+[docs] + @validate_call + def add_samples(self, open_times_ms: Sequence[PositiveFloat], weights_g: Sequence[PositiveFloat]): + incoming = np.rec.fromarrays([open_times_ms, weights_g], dtype=self._dtype) + self._data = np.append(self._data, incoming) + self._data = np.sort(self._data) + self._update_fit()
+ + +
+[docs] + def clear_data(self): + self._data = np.empty((0,), dtype=self._dtype) + self._update_fit()
+ + + @property + def open_times_ms(self) -> np.ndarray: + return self._data['open_times_ms'] + + @property + def weights_g(self) -> np.ndarray: + return self._data['weights_g'] + + @property + def volumes_ul(self) -> np.ndarray: + return self._data['weights_g'] * 1e3 + + def _update_fit(self) -> None: + if len(self._data) >= 2: + with warnings.catch_warnings(): + warnings.simplefilter('ignore') + try: + c, _ = scipy.optimize.curve_fit( + self._fcn, self.open_times_ms, self.volumes_ul, p0=[0, 0, 0], bounds=([-np.inf, 0, 0], np.inf) + ) + except RuntimeError: + c = [np.nan, np.nan, np.nan] + else: + c = [np.nan, np.nan, np.nan] + self._polynomial = Polynomial(coef=c) + +
+[docs] + @validate_call + def ul2ms(self, volume_ul: NonNegativeFloat | Iterable[NonNegativeFloat]) -> NonNegativeFloat | np.ndarray: + if isinstance(volume_ul, Iterable): + return np.array([self.ul2ms(v) for v in volume_ul]) + elif volume_ul == 0.0: + return 0.0 + else: + return max(np.append((self._polynomial - volume_ul).roots(), 0.0))
+ + +
+[docs] + @validate_call + def ms2ul(self, time_ms: NonNegativeFloat | Iterable[NonNegativeFloat]) -> NonNegativeFloat | np.ndarray: + if isinstance(time_ms, Iterable): + return np.array([self.ms2ul(t) for t in time_ms]) + elif time_ms == 0.0: + return 0.0 + else: + return max(np.append(self._polynomial(time_ms), 0.0))
+
+ + + +
+[docs] +class Valve: +
+[docs] + def __init__(self, settings: HardwareSettingsValve): + self._settings = settings + volumes_ul = settings.WATER_CALIBRATION_WEIGHT_PERDROP + weights_g = [volume / 1e3 for volume in volumes_ul] + self.values = ValveValues(settings.WATER_CALIBRATION_OPEN_TIMES, weights_g)
+ + + @property + def calibration_date(self) -> datetime.date: + return self._settings.WATER_CALIBRATION_DATE + + @property + def is_calibrated(self) -> bool: + return datetime.date.today() >= self.calibration_date + + @property + def calibration_range(self) -> list[float, float]: + return self._settings.WATER_CALIBRATION_RANGE + + @property + def new_calibration_open_times(self) -> set[float]: + return set(np.linspace(self.calibration_range[0], self.calibration_range[1], self._settings.WATER_CALIBRATION_N)) + + @property + def free_reward_time_sec(self) -> float: + return self.values.ul2ms(self._settings.FREE_REWARD_VOLUME_UL) / 1000.0 + + @property + def free_reward_volume_ul(self) -> float: + return self._settings.FREE_REWARD_VOLUME_UL + + @property + def settings(self) -> HardwareSettingsValve: + settings = self._settings + settings.WATER_CALIBRATION_OPEN_TIMES = self.values.open_times_ms + settings.WATER_CALIBRATION_WEIGHT_PERDROP = self.values.volumes_ul + return settings
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig/version_management.html b/_modules/iblrig/version_management.html new file mode 100644 index 000000000..4a7321691 --- /dev/null +++ b/_modules/iblrig/version_management.html @@ -0,0 +1,527 @@ + + + + + + iblrig.version_management — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for iblrig.version_management

+import logging
+import re
+from collections.abc import Callable
+from functools import cache
+from pathlib import Path
+from subprocess import STDOUT, CalledProcessError, SubprocessError, check_call, check_output
+from typing import Any, Literal
+
+import requests
+from packaging import version
+
+from iblrig import __version__
+from iblrig.constants import BASE_DIR, IS_GIT, IS_VENV
+from iblrig.tools import cached_check_output, internet_available
+
+log = logging.getLogger(__name__)
+
+
+
+[docs] +def check_for_updates() -> tuple[bool, str]: + """ + Check for updates to the iblrig software. + + This function compares the locally installed version of iblrig with the + latest available version to determine if an update is available. + + Returns + ------- + tuple[bool, Union[str, None]]: A tuple containing two elements. + - A boolean indicating whether an update is available. + - A string representing the latest available version, or None if + no remote version information is available. + """ + log.debug('Checking for updates ...') + + update_available = False + v_local = get_local_version() + v_remote = get_remote_version() + + if v_local and v_remote: + update_available = v_remote.base_version > v_local.base_version + if update_available: + log.info(f'Update to iblrig {v_remote.base_version} available') + else: + log.debug('No update available') + + return update_available, v_remote.base_version if v_remote else ''
+ + + +
+[docs] +def get_local_version() -> version.Version | None: + """ + Parse the local version string to obtain a Version object. + + This function attempts to parse the local version string (__version__) + and returns a Version object representing the parsed version. If the + parsing fails, it logs an error and returns None. + + Returns + ------- + Union[version.Version, None] + A Version object representing the parsed local version, or None if + parsing fails. + """ + try: + log.debug('Parsing local version string') + return version.parse(__version__) + except (version.InvalidVersion, TypeError): + log.error(f'Could not parse local version string: {__version__}') + return None
+ + + +
+[docs] +def get_detailed_version_string(v_basic: str) -> str: + """ + Generate a detailed version string based on a basic version string. + + This function takes a basic version string (major.minor.patch) and generates + a detailed version string by querying Git for additional version information. + The detailed version includes commit number of commits since the last tag, + and Git status (dirty or broken). It is designed to fail safely. + + Parameters + ---------- + v_basic : str + A basic version string in the format 'major.minor.patch'. + + Returns + ------- + str + A detailed version string containing version information retrieved + from Git, or the original basic version string if Git information + cannot be obtained. + + Notes + ----- + This method will only work with installations managed through Git. + """ + if not internet_available(): + return v_basic + + if not IS_GIT: + log.error('This installation of IBLRIG is not managed through git.') + return v_basic + + # sanitize & check if input only consists of three fields - major, minor and patch - separated by dots + v_sanitized = re.sub(r'^(\d+\.\d+\.\d+).*$$', r'\1', v_basic) + if not re.match(r'^\d+\.\d+\.\d+$', v_sanitized): + log.error(f"Couldn't parse version string: {v_basic}") + return v_basic + + # get details through `git describe` + try: + get_remote_tags() + v_detailed = check_output( + ['git', 'describe', '--dirty', '--broken', '--match', v_sanitized, '--tags', '--long'], + cwd=BASE_DIR, + text=True, + timeout=1, + stderr=STDOUT, + ) + except (SubprocessError, CalledProcessError) as e: + log.debug(e, exc_info=True) + return v_basic + + # apply a bit of regex magic for formatting & return the detailed version string + v_detailed = re.sub(r'^((?:[\d+\.])+)(-[1-9]\d*)?(?:-0\d*)?(?:-\w+)(-dirty|-broken)?\n?$', r'\1\2\3', v_detailed) + v_detailed = re.sub(r'-(\d+)', r'.post\1', v_detailed) + v_detailed = re.sub(r'\-(dirty|broken)', r'+\1', v_detailed) + return v_detailed
+ + + +OnErrorLiteral = Literal['raise', 'log', 'silence'] + + +
+[docs] +def call_git(*args: str, cache_output: bool = True, on_error: OnErrorLiteral = 'raise') -> str | None: + """ + Call a git command with the specified arguments. + + This function executes a git command with the provided arguments. It can cache the output of the command + and handle errors based on the specified behavior. + + Parameters + ---------- + *args : str + The arguments to pass to the git command. + cache_output : bool, optional + Whether to cache the output of the command. Default is True. + on_error : str, optional + The behavior when an error occurs. Either + - 'raise': raise the exception (default), + - 'log': log the exception, or + - 'silence': suppress the exception. + + Returns + ------- + str or None + The output of the git command as a string, or None if an error occurred. + + Raises + ------ + RuntimeError + If the installation is not managed through git and on_error is set to 'raise'. + SubprocessError + If the command fails and on_error is set to 'raise'. + """ + kwargs: dict[str, Any] = {'args': ('git', *args), 'cwd': BASE_DIR, 'timeout': 5, 'text': True} + if not IS_GIT: + message = 'This installation of iblrig is not managed through git' + if on_error == 'raise': + raise RuntimeError(message) + elif on_error == 'log': + log.error(message) + return None + try: + output = cached_check_output(**kwargs) if cache_output else check_output(**kwargs) + return str(output).strip() + except SubprocessError as e: + if on_error == 'raise': + raise e + elif on_error == 'log': + log.exception(e) + return None
+ + + +
+[docs] +def get_branch(): + """ + Get the Git branch of the iblrig installation. + + Returns + ------- + str or None + The Git branch of the iblrig installation, or None if it cannot be determined. + """ + return call_git('rev-parse', '--abbrev-ref', 'HEAD', on_error='log')
+ + + +
+[docs] +def get_commit_hash(short: bool = True): + """ + Get the hash of the currently checked out commit of the iblrig installation. + + Parameters + ---------- + short : bool, optional + Whether to return the short hash of the commit hash. Default is True. + + Returns + ------- + str or None + Hash of the currently checked out commit, or None if it cannot be determined. + """ + args = ['rev-parse', '--short', 'HEAD'] if short else ['rev-parse', 'HEAD'] + return call_git(*args, on_error='log')
+ + + +
+[docs] +def get_remote_tags() -> None: + """ + Fetch remote Git tags if not already fetched. + + This function fetches remote Git tags if they have not been fetched already. + If tags are already fetched, it does nothing. If the installation is not + managed through Git, it logs an error. + + Returns + ------- + None + + Notes + ----- + This method will only work with installations managed through Git. + """ + if not internet_available(): + return + if (branch := get_branch()) is None: + return + call_git('fetch', 'origin', branch, '-t', '-q', '-f', on_error='log')
+ + + +
+[docs] +@cache +def get_changelog() -> str: + """ + Retrieve the changelog for the iblrig installation. + + This function retrieves and caches the changelog for the iblrig installation + based on the current Git branch. If the changelog is already cached, it + returns the cached value. If not, it attempts to fetch the changelog from + the GitHub repository or read it locally if the remote fetch fails. + + Returns + ------- + str + The changelog for the iblrig installation. + + Notes + ----- + This method relies on the presence of a CHANGELOG.md file either in the + repository or locally. + """ + try: + if (branch := get_branch()) is None: + raise RuntimeError() + changelog = requests.get( + f'https://raw.githubusercontent.com/int-brain-lab/iblrig/{branch}/CHANGELOG.md', allow_redirects=True + ).text + except (requests.RequestException, RuntimeError): + with open(Path(BASE_DIR).joinpath('CHANGELOG.md')) as f: + changelog = f.read() + return changelog
+ + + +
+[docs] +def get_remote_version() -> version.Version | None: + """ + Retrieve the remote version of iblrig from the Git repository. + + This function fetches and parses the remote version of the iblrig software + from the Git repository. It uses Git tags to identify available versions. + + Returns + ------- + Union[version.Version, None] + A Version object representing the remote version if successfully obtained, + or None if the remote version cannot be retrieved. + + Notes + ----- + This method will only work with installations managed through Git. + """ + if not internet_available(): + log.error('Cannot obtain remote version: Not connected to internet') + return None + + references = call_git('ls-remote', '-t', '-q', '--exit-code', '--refs', 'origin', 'tags', '*', on_error='log') + + try: + log.debug('Parsing local version string') + get_remote_version.remote_version = max([version.parse(v) for v in re.findall(r'/(\d+\.\d+\.\d+)', references)]) + return get_remote_version.remote_version + except (version.InvalidVersion, TypeError): + log.error('Could not parse remote version string') + return None
+ + + +
+[docs] +def is_dirty() -> bool: + """ + Check if the Git working directory is dirty (has uncommitted changes). + + Uses 'git diff --quiet' to determine if there are uncommitted changes in the Git repository. + + Returns + ------- + bool: True if the directory is dirty (has uncommitted changes) or an error occurs during execution, + False if the directory is clean (no uncommitted changes). + """ + try: + return check_call(['git', 'diff', '--quiet'], cwd=BASE_DIR) != 0 + except CalledProcessError: + return True
+ + + +
+[docs] +def check_upgrade_prerequisites(exception_handler: Callable | None = None, *args, **kwargs) -> None: + """Check prerequisites for upgrading IBLRIG. + + This function verifies the prerequisites necessary for upgrading IBLRIG. It checks for + internet connectivity, whether the IBLRIG installation is managed through Git, and + whether the script is running within the IBLRIG virtual environment. + + Parameters + ---------- + exception_handler : Callable, optional + An optional callable that handles exceptions if raised during the check. + If provided, it will be called with the exception as the first argument, + followed by any additional positional arguments (*args), and any + additional keyword arguments (**kwargs). + + *args : Additional positional arguments + Any additional positional arguments needed by the `exception_handler` callable. + + **kwargs : Additional keyword arguments + Any additional keyword arguments needed by the `exception_handler` callable. + + + Raises + ------ + ConnectionError + If there is no connection to the internet. + RuntimeError + If the IBLRIG installation is not managed through Git, or + if the script is not running within the IBLRIG virtual environment. + """ + try: + if not internet_available(): + raise ConnectionError('No connection to internet.') + if not IS_GIT: + raise RuntimeError('This installation of IBLRIG is not managed through Git.') + if not IS_VENV: + raise RuntimeError('You need to be in the IBLRIG virtual environment in order to upgrade.') + except (ConnectionError, RuntimeError) as e: + if callable(exception_handler): + exception_handler(e, *args, **kwargs) + else: + raise e
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_ImagingChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_ImagingChoiceWorld/task.html new file mode 100644 index 000000000..05ffa43a7 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_ImagingChoiceWorld/task.html @@ -0,0 +1,166 @@ + + + + + + iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task

+from iblrig.base_choice_world import BiasedChoiceWorldSession
+from iblrig.misc import get_task_arguments, truncated_exponential
+
+
+
+[docs] +class Session(BiasedChoiceWorldSession): + protocol_name = '_iblrig_tasks_imagingChoiceWorld' + +
+[docs] + @staticmethod + def draw_quiescent_period() -> float: + """ + Draw the quiescent period. + + For this task we double the quiescence period texp draw and remove the absolute offset of 200ms. + The resulting is a truncated exp distribution between 400ms and 1 sec + + TODO: This is a broken overload and never actually called - quiescent periods are not changed from BiasedCW + """ + return truncated_exponential(scale=0.35 * 2, min_value=0.2 * 2, max_value=0.5 * 2)
+
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_advancedChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_advancedChoiceWorld/task.html new file mode 100644 index 000000000..6727a433d --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_advancedChoiceWorld/task.html @@ -0,0 +1,296 @@ + + + + + + iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task

+from pathlib import Path
+
+import numpy as np
+import pandas as pd
+import yaml
+
+import iblrig.misc
+from iblrig.base_choice_world import NTRIALS_INIT, ActiveChoiceWorldSession
+
+# read defaults from task_parameters.yaml
+with open(Path(__file__).parent.joinpath('task_parameters.yaml')) as f:
+    DEFAULTS = yaml.safe_load(f)
+
+
+
+[docs] +class Session(ActiveChoiceWorldSession): + """ + Advanced Choice World is the ChoiceWorld task using fixed 50/50 probability for the side + and contrasts defined in the parameters. + It differs from TrainingChoiceWorld in that it does not implement adaptive contrasts or debiasing, + and it differs from BiasedChoiceWorld in that it does not implement biased blocks. + """ + + protocol_name = '_iblrig_tasks_advancedChoiceWorld' + +
+[docs] + def __init__( + self, + *args, + contrast_set: list[float] = DEFAULTS['CONTRAST_SET'], + probability_set: list[float] = DEFAULTS['PROBABILITY_SET'], + reward_set_ul: list[float] = DEFAULTS['REWARD_SET_UL'], + position_set: list[float] = DEFAULTS['POSITION_SET'], + stim_gain: float = DEFAULTS['STIM_GAIN'], + stim_reverse: float = DEFAULTS['STIM_REVERSE'], + **kwargs, + ): + super().__init__(*args, **kwargs) + nc = len(contrast_set) + assert len(probability_set) in [nc, 1], 'probability_set must be a scalar or have the same length as contrast_set' + assert len(reward_set_ul) in [nc, 1], 'reward_set_ul must be a scalar or have the same length as contrast_set' + assert len(position_set) == nc, 'position_set must have the same length as contrast_set' + self.task_params['CONTRAST_SET'] = contrast_set + self.task_params['PROBABILITY_SET'] = probability_set + self.task_params['REWARD_SET_UL'] = reward_set_ul + self.task_params['POSITION_SET'] = position_set + self.task_params['STIM_GAIN'] = stim_gain + self.task_params['STIM_REVERSE'] = stim_reverse + # it is easier to work with parameters as a dataframe + self.df_contingencies = pd.DataFrame(columns=['contrast', 'probability', 'reward_amount_ul', 'position']) + self.df_contingencies['contrast'] = contrast_set + self.df_contingencies['probability'] = np.float64(probability_set if len(probability_set) == nc else probability_set[0]) + self.df_contingencies['reward_amount_ul'] = reward_set_ul if len(reward_set_ul) == nc else reward_set_ul[0] + self.df_contingencies['position'] = position_set + # normalize the probabilities + self.df_contingencies.loc[:, 'probability'] = self.df_contingencies.loc[:, 'probability'] / np.sum( + self.df_contingencies.loc[:, 'probability'] + ) + # update the PROBABILITY LEFT field to reflect the probabilities in the parameters above + self.task_params['PROBABILITY_LEFT'] = np.sum( + self.df_contingencies['probability'] * (self.df_contingencies['position'] < 0) + ) + self.trials_table['debias_trial'] = np.zeros(NTRIALS_INIT, dtype=bool)
+ + +
+[docs] + def draw_next_trial_info(self, **kwargs): + nc = self.df_contingencies.shape[0] + ic = np.random.choice(np.arange(nc), p=self.df_contingencies['probability']) + # now calling the super class with the proper parameters + super().draw_next_trial_info( + pleft=self.task_params.PROBABILITY_LEFT, + contrast=self.df_contingencies.at[ic, 'contrast'], + position=self.df_contingencies.at[ic, 'position'], + reward_amount=self.df_contingencies.at[ic, 'reward_amount_ul'], + )
+ + + @property + def reward_amount(self): + return self.task_params.REWARD_AMOUNTS_UL[0] + +
+[docs] + @staticmethod + def extra_parser(): + """:return: argparse.parser()""" + parser = super(Session, Session).extra_parser() + parser.add_argument( + '--contrast_set', + option_strings=['--contrast_set'], + dest='contrast_set', + default=DEFAULTS['CONTRAST_SET'], + nargs='+', + type=float, + help='Set of contrasts to present', + ) + parser.add_argument( + '--probability_set', + option_strings=['--probability_set'], + dest='probability_set', + default=DEFAULTS['PROBABILITY_SET'], + nargs='+', + type=float, + help='Probabilities of each contrast in contrast_set. If scalar all contrasts are equiprobable', + ) + parser.add_argument( + '--reward_set_ul', + option_strings=['--reward_set_ul'], + dest='reward_set_ul', + default=DEFAULTS['REWARD_SET_UL'], + nargs='+', + type=float, + help='Reward for contrast in contrast set.', + ) + parser.add_argument( + '--position_set', + option_strings=['--position_set'], + dest='position_set', + default=DEFAULTS['POSITION_SET'], + nargs='+', + type=float, + help='Position for each contrast in contrast set.', + ) + parser.add_argument( + '--stim_gain', + option_strings=['--stim_gain'], + dest='stim_gain', + default=DEFAULTS['STIM_GAIN'], + type=float, + help=f'Visual angle/wheel displacement ' f'(deg/mm, default: {DEFAULTS["STIM_GAIN"]})', + ) + parser.add_argument( + '--stim_reverse', + option_strings=['--stim_reverse'], + action='store_true', + dest='stim_reverse', + help='Inverse relationship of wheel to stimulus movement', + ) + return parser
+ + +
+[docs] + def next_trial(self): + # update counters + self.trial_num += 1 + # save and send trial info to bonsai + self.draw_next_trial_info(pleft=self.task_params.PROBABILITY_LEFT)
+
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_biasedChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_biasedChoiceWorld/task.html new file mode 100644 index 000000000..e25efec51 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_biasedChoiceWorld/task.html @@ -0,0 +1,150 @@ + + + + + + iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task

+import iblrig.misc
+from iblrig.base_choice_world import BiasedChoiceWorldSession
+
+
+
+[docs] +class Session(BiasedChoiceWorldSession): ...
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_ephysChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_ephysChoiceWorld/task.html new file mode 100644 index 000000000..e3cc398f0 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_ephysChoiceWorld/task.html @@ -0,0 +1,218 @@ + + + + + + iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task

+"""
+The ephys choice world task is the same as the biased choice world except that
+the trials are pregenerated and saved in a fixture file.
+"""
+
+from pathlib import Path
+
+import pandas as pd
+
+import iblrig.misc
+from iblrig.base_choice_world import BiasedChoiceWorldSession
+
+
+
+[docs] +class Session(BiasedChoiceWorldSession): + protocol_name = '_iblrig_tasks_ephysChoiceWorld' + +
+[docs] + def __init__(self, *args, session_template_id=0, **kwargs): + super().__init__(*args, **kwargs) + self.task_params.SESSION_TEMPLATE_ID = session_template_id + self.trials_table = self.get_session_template(session_template_id) + # reconstruct the block dataframe from the trials table + self.blocks_table = self.trials_table.groupby('block_num').agg( + probability_left=pd.NamedAgg(column='stim_probability_left', aggfunc='first'), + block_length=pd.NamedAgg(column='stim_probability_left', aggfunc='count'), + )
+ + +
+[docs] + def next_trial(self): + self.trial_num += 1 + trial_params = self.trials_table.iloc[self.trial_num].drop(['index', 'trial_num']).to_dict() + self.block_num = trial_params['block_num'] + self.draw_next_trial_info(**trial_params)
+ + +
+[docs] + @staticmethod + def get_session_template(session_template_id: int) -> pd.DataFrame: + """ + Return the pre-generated trials dataframe from the 12 fixtures according to the template ID. + + Parameters + ---------- + session_template_id : int + Session template ID (0-11). + """ + trials_table = pd.read_parquet(Path(__file__).parent.joinpath('trials_fixtures.pqt')) + trials_table = ( + trials_table.loc[trials_table['session_id'] == session_template_id].reindex().drop(columns=['session_id']) + ).reset_index() + return trials_table
+ + +
+[docs] + @staticmethod + def extra_parser(): + """:return: argparse.parser()""" + parser = super(Session, Session).extra_parser() + parser.add_argument( + '--session_template_id', + option_strings=['--session_template_id'], + dest='session_template_id', + default=0, + type=int, + help='pre-generated session index (zero-based)', + ) + return parser
+
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_habituationChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_habituationChoiceWorld/task.html new file mode 100644 index 000000000..383f43cd7 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_habituationChoiceWorld/task.html @@ -0,0 +1,150 @@ + + + + + + iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task

+import iblrig.misc
+from iblrig.base_choice_world import HabituationChoiceWorldSession
+
+
+
+[docs] +class Session(HabituationChoiceWorldSession): ...
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_neuroModulatorChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_neuroModulatorChoiceWorld/task.html new file mode 100644 index 000000000..6a682be65 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_neuroModulatorChoiceWorld/task.html @@ -0,0 +1,452 @@ + + + + + + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task

+import logging
+
+import numpy as np
+from pydantic import NonNegativeFloat
+
+import iblrig.misc
+from iblrig.base_choice_world import BiasedChoiceWorldSession, BiasedChoiceWorldTrialData
+from iblrig.hardware import SOFTCODE
+from pybpodapi.protocol import StateMachine
+
+REWARD_AMOUNTS_UL = (1, 3)
+log = logging.getLogger(__name__)
+
+
+
+[docs] +class NeuroModulatorChoiceTrialData(BiasedChoiceWorldTrialData): + omit_feedback: bool + choice_delay: NonNegativeFloat
+ + + +
+[docs] +class Session(BiasedChoiceWorldSession): + protocol_name = '_iblrig_tasks_neuromodulatorChoiceWorld' + TrialDataModel = NeuroModulatorChoiceTrialData + +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs)
+ + +
+[docs] + def next_trial(self): + super().next_trial() + # then there is a probability of omitting feedback regardless of the choice + self.trials_table.at[self.trial_num, 'omit_feedback'] = np.random.random() < self.task_params.OMIT_FEEDBACK_PROBABILITY + + # then drawing the delay for the choice + choice_delay_strategy = 'binned' + if choice_delay_strategy == 'binary': # this is a choice with probabilities 1/3 2/3 + self.trials_table.at[self.trial_num, 'choice_delay'] = np.random.choice([1.5, 3.0], p=[2 / 3, 1 / 3]) + elif choice_delay_strategy == 'uniform': # uniform probability draw between 1.5s and 3s + self.trials_table.at[self.trial_num, 'choice_delay'] = np.random.random() * 1.5 + 1.5 + elif choice_delay_strategy == 'binned': # 5 valures from 0 to 2.5 secs The "Charline Way" + self.trials_table.at[self.trial_num, 'choice_delay'] = np.random.choice(np.linspace(0, 2.5, 3)) + + if self.task_params.VARIABLE_REWARDS: + # the reward is a draw within an uniform distribution between 3 and 1 + reward_amount = 1.5 if self.block_num == 0 else np.random.choice(REWARD_AMOUNTS_UL, p=[0.8, 0.2]) + self.trials_table.at[self.trial_num, 'reward_amount'] = reward_amount
+ + + @property + def omit_feedback(self): + return self.trials_table.at[self.trial_num, 'omit_feedback'] + + @property + def choice_to_feedback_delay(self): + return self.trials_table.at[self.trial_num, 'choice_delay'] + +
+[docs] + def get_state_machine_trial(self, i): + sma = StateMachine(self.bpod) + + if i == 0: # First trial exception start camera + session_delay_start = self.task_params.get('SESSION_DELAY_START', 0) + log.info('First trial initializing, will move to next trial only if:') + log.info('1. camera is detected') + log.info(f'2. {session_delay_start} sec have elapsed') + sma.add_state( + state_name='trial_start', + state_timer=0, + state_change_conditions={'Port1In': 'delay_initiation'}, + output_actions=[('SoftCode', SOFTCODE.TRIGGER_CAMERA), ('BNC1', 255)], + ) # start camera + sma.add_state( + state_name='delay_initiation', + state_timer=session_delay_start, + output_actions=[], + state_change_conditions={'Tup': 'reset_rotary_encoder'}, + ) + else: + sma.add_state( + state_name='trial_start', + state_timer=0, # ~100µs hardware irreducible delay + state_change_conditions={'Tup': 'reset_rotary_encoder'}, + output_actions=[self.bpod.actions.stop_sound, ('BNC1', 255)], + ) # stop all sounds + + sma.add_state( + state_name='reset_rotary_encoder', + state_timer=0, + output_actions=[self.bpod.actions.rotary_encoder_reset], + state_change_conditions={'Tup': 'quiescent_period'}, + ) + + sma.add_state( # '>back' | '>reset_timer' + state_name='quiescent_period', + state_timer=self.quiescent_period, + output_actions=[], + state_change_conditions={ + 'Tup': 'stim_on', + self.movement_left: 'reset_rotary_encoder', + self.movement_right: 'reset_rotary_encoder', + }, + ) + + sma.add_state( + state_name='stim_on', + state_timer=0.1, + output_actions=[self.bpod.actions.bonsai_show_stim], + state_change_conditions={'Tup': 'interactive_delay', 'BNC1High': 'interactive_delay', 'BNC1Low': 'interactive_delay'}, + ) + + sma.add_state( + state_name='interactive_delay', + state_timer=self.task_params.INTERACTIVE_DELAY, + output_actions=[], + state_change_conditions={'Tup': 'play_tone'}, + ) + + sma.add_state( + state_name='play_tone', + state_timer=0.1, + output_actions=[self.bpod.actions.play_tone, ('BNC1', 255)], + state_change_conditions={'Tup': 'reset2_rotary_encoder', 'BNC2High': 'reset2_rotary_encoder'}, + ) + + sma.add_state( + state_name='reset2_rotary_encoder', + state_timer=0.05, + output_actions=[self.bpod.actions.rotary_encoder_reset], + state_change_conditions={'Tup': 'closed_loop'}, + ) + + if self.omit_feedback: + sma.add_state( + state_name='closed_loop', + state_timer=self.task_params.RESPONSE_WINDOW, + output_actions=[self.bpod.actions.bonsai_closed_loop], + state_change_conditions={'Tup': 'omit_no_go', self.event_error: 'omit_error', self.event_reward: 'omit_correct'}, + ) + else: + sma.add_state( + state_name='closed_loop', + state_timer=self.task_params.RESPONSE_WINDOW, + output_actions=[self.bpod.actions.bonsai_closed_loop], + state_change_conditions={ + 'Tup': 'delay_no_go', + self.event_error: 'delay_error', + self.event_reward: 'delay_reward', + }, + ) + + # here we create 3 separates states to disambiguate the choice of the mouse + # in the output data - apart from the name they are exactly the same state + for state_name in ['omit_error', 'omit_correct', 'omit_no_go']: + sma.add_state( + state_name=state_name, + state_timer=( + self.task_params.FEEDBACK_NOGO_DELAY_SECS + + self.task_params.FEEDBACK_ERROR_DELAY_SECS + + self.task_params.FEEDBACK_CORRECT_DELAY_SECS + ) + / 3, + output_actions=[], + state_change_conditions={'Tup': 'hide_stim'}, + ) + + sma.add_state( + state_name='delay_no_go', + state_timer=self.choice_to_feedback_delay, + state_change_conditions={'Tup': 'no_go'}, + output_actions=[], + ) + + sma.add_state( + state_name='no_go', + state_timer=self.task_params.FEEDBACK_NOGO_DELAY_SECS, + output_actions=[self.bpod.actions.bonsai_hide_stim, self.bpod.actions.play_noise], + state_change_conditions={'Tup': 'exit_state'}, + ) + + sma.add_state( + state_name='delay_error', + state_timer=self.choice_to_feedback_delay, + state_change_conditions={'Tup': 'freeze_error'}, + output_actions=[], + ) + + sma.add_state( + state_name='freeze_error', + state_timer=0, + output_actions=[self.bpod.actions.bonsai_freeze_stim], + state_change_conditions={'Tup': 'error'}, + ) + + sma.add_state( + state_name='error', + state_timer=self.task_params.FEEDBACK_ERROR_DELAY_SECS, + output_actions=[self.bpod.actions.play_noise], + state_change_conditions={'Tup': 'hide_stim'}, + ) + + sma.add_state( + state_name='delay_reward', + state_timer=self.choice_to_feedback_delay, + state_change_conditions={'Tup': 'freeze_reward'}, + output_actions=[], + ) + + sma.add_state( + state_name='freeze_reward', + state_timer=0, + output_actions=[self.bpod.actions.bonsai_freeze_stim], + state_change_conditions={'Tup': 'reward'}, + ) + + sma.add_state( + state_name='reward', + state_timer=self.reward_time, + output_actions=[('Valve1', 255)], + state_change_conditions={'Tup': 'correct'}, + ) + + sma.add_state( + state_name='correct', + state_timer=self.task_params.FEEDBACK_CORRECT_DELAY_SECS, + output_actions=[], + state_change_conditions={'Tup': 'hide_stim'}, + ) + + sma.add_state( + state_name='hide_stim', + state_timer=0.1, + output_actions=[self.bpod.actions.bonsai_hide_stim], + state_change_conditions={'Tup': 'exit_state', 'BNC1High': 'exit_state', 'BNC1Low': 'exit_state'}, + ) + + sma.add_state( + state_name='exit_state', state_timer=0.5, output_actions=[('BNC1', 255)], state_change_conditions={'Tup': 'exit'} + ) + return sma
+
+ + + +
+[docs] +class SessionRelatedBlocks(Session): + """ + In this scenario, the blocks define a poor and a rich side. + The probability blocks and reward blocks structure is staggered so that we explore all configurations every 4 blocks + P0 P1 P2 P1 P2 P1 P2 P1 P2 + R0 R1 R1 R2 R2 R1 R1 R2 R2 + """ + + # from iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task import SessionRelatedBlocks + # sess = SessionRelatedBlocks() +
+[docs] + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.trials_table['omit_feedback'] = np.zeros(self.trials_table.shape[0], dtype=bool) + self.trials_table['choice_delay'] = np.zeros(self.trials_table.shape[0], dtype=np.float32) + self.trials_table['probability_left_rich'] = np.zeros(self.trials_table.shape[0], dtype=np.float32) + self.blocks_table['probability_left_rich'] = np.zeros(self.blocks_table.shape[0], dtype=np.float32) + self.BLOCK_REWARD_STAGGER = np.random.randint(0, 2)
+ + +
+[docs] + def new_block(self): + super(Session, self).new_block() + if self.block_num == 0: + probability_left_rich = 0.5 + elif int((self.block_num + self.BLOCK_REWARD_STAGGER) / 2 % 2): + probability_left_rich = 0.8 + else: + probability_left_rich = 0.2 + self.blocks_table.at[self.block_num, 'probability_left_rich'] = probability_left_rich
+ + +
+[docs] + def next_trial(self): + super().next_trial() + self.trials_table.at[self.trial_num, 'reward_amount'] = self.draw_reward_amount() + prich = self.blocks_table.loc[self.block_num, 'probability_left_rich'] + self.trials_table.at[self.trial_num, 'probability_left_rich'] = prich
+ + +
+[docs] + def draw_reward_amount(self): + # FIXME check: this has 0.5 probability of being correct !!! + reward_amounts = (1, 3) # poor and rich + plr = self.blocks_table.at[self.block_num, 'probability_left_rich'] + if np.sign(self.position): # noqa: SIM108 + probas = [plr, (1 - plr)] # right + else: + probas = [(1 - plr), plr] # left + return np.random.choice(reward_amounts, p=probas)
+
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_passiveChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_passiveChoiceWorld/task.html new file mode 100644 index 000000000..bdbab5469 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_passiveChoiceWorld/task.html @@ -0,0 +1,289 @@ + + + + + + iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task

+import logging
+import sys
+import time
+from datetime import timedelta
+from pathlib import Path
+
+import pandas as pd
+import yaml
+
+import iblrig.misc
+from iblrig.base_choice_world import ChoiceWorldSession
+
+log = logging.getLogger('iblrig.task')
+
+# read defaults from task_parameters.yaml
+with open(Path(__file__).parent.joinpath('task_parameters.yaml')) as f:
+    DEFAULTS = yaml.safe_load(f)
+
+
+
+[docs] +class Session(ChoiceWorldSession): + protocol_name = '_iblrig_tasks_passiveChoiceWorld' + +
+[docs] + def __init__( + self, + *args, + session_template_id=0, + duration_spontaneous: int = DEFAULTS['SPONTANEOUS_ACTIVITY_SECONDS'], + skip_event_replay: bool = DEFAULTS['SKIP_EVENT_REPLAY'], + **kwargs, + ): + self.extractor_tasks = ['PassiveRegisterRaw', 'PassiveTask'] + super(ChoiceWorldSession, self).__init__(**kwargs) + self.task_params.SESSION_TEMPLATE_ID = session_template_id + all_trials = pd.read_parquet(Path(__file__).parent.joinpath('passiveChoiceWorld_trials_fixtures.pqt')) + self.trials_table = all_trials[all_trials['session_id'] == self.task_params.SESSION_TEMPLATE_ID].copy() + self.trials_table['reward_valve_time'] = self.compute_reward_time(amount_ul=self.trials_table['reward_amount']) + assert duration_spontaneous < 60 * 60 * 24 + self.task_params['SPONTANEOUS_ACTIVITY_SECONDS'] = duration_spontaneous + self.task_params['SKIP_EVENT_REPLAY'] = skip_event_replay + if self.hardware_settings['MAIN_SYNC']: + log.error('PassiveChoiceWorld extraction not supported for Bpod-only sessions!')
+ + +
+[docs] + @staticmethod + def extra_parser(): + """:return: argparse.parser()""" + parser = super(Session, Session).extra_parser() + parser.add_argument( + '--session_template_id', + option_strings=['--session_template_id'], + dest='session_template_id', + default=0, + type=int, + help='pre-generated session index (zero-based)', + ) + parser.add_argument( + '--duration_spontaneous', + option_strings=['--duration_spontaneous'], + dest='duration_spontaneous', + default=DEFAULTS['SPONTANEOUS_ACTIVITY_SECONDS'], + type=int, + help=f'duration of spontaneous activity in seconds ' f'(default: {DEFAULTS["SPONTANEOUS_ACTIVITY_SECONDS"]} s)', + ) + parser.add_argument( + '--skip_event_replay', + option_strings=['--skip_event_replay'], + action='store_true', + dest='skip_event_replay', + help='skip replay of events', + ) + return parser
+ + +
+[docs] + def start_hardware(self): + if not self.is_mock: + self.start_mixin_frame2ttl() + self.start_mixin_bpod() + self.start_mixin_valve() + self.start_mixin_sound() + self.start_mixin_bonsai_cameras() + self.start_mixin_bonsai_microphone() + self.start_mixin_rotary_encoder()
+ + +
+[docs] + def get_state_machine_trial(self, *args, **kwargs): + pass
+ + +
+[docs] + def next_trial(self): + pass
+ + + def _run(self): + """Run the task with the actual state machine.""" + self.trigger_bonsai_cameras() + + # Run the passive part i.e. spontaneous activity and RFMapping stim + self.run_passive_visual_stim(sa_time=timedelta(seconds=self.task_params['SPONTANEOUS_ACTIVITY_SECONDS'])) + + if self.task_params['SKIP_EVENT_REPLAY'] is True: + log.info('Skipping replay of task events') + return + + # run the replay of task events: V for valve, T for tone, N for noise, G for gratings + log.info('Starting replay of task events') + action_show_stim = self.bpod.actions['bonsai_show_stim'][1] + action_hide_stim = self.bpod.actions['bonsai_hide_stim'][1] + byte_show_stim = self.bpod.serial_messages[action_show_stim]['message'][-1] + byte_hide_stim = self.bpod.serial_messages[action_hide_stim]['message'][-1] + + if not self.is_mock: + self.start_mixin_bonsai_visual_stimulus() + for trial_num, trial in self.trials_table.iterrows(): + self.trial_num = trial_num + log.info(f'Delay: {trial.stim_delay}; ID: {trial.stim_type}; Count: {self.trial_num}/300') + sys.stdout.flush() + time.sleep(trial.stim_delay) + if trial.stim_type == 'V': + self.valve_open(self.reward_time) + elif trial.stim_type == 'T': + self.sound_play_tone(state_timer=0.102) + elif trial.stim_type == 'N': + self.sound_play_noise(state_timer=0.510) + elif trial.stim_type == 'G': + # this will send the current trial info to the visual stim + # we need to make sure Bonsai is in a state to display stimuli + self.send_trial_info_to_bonsai() + self.bonsai_visual_udp_client.send_message(r'/re', byte_show_stim) + time.sleep(0.3) # todo: this is a very inaccurate way of controlling stim duration! + self.bonsai_visual_udp_client.send_message(r'/re', byte_hide_stim) + if self.paths.SESSION_FOLDER.joinpath('.stop').exists(): + self.paths.SESSION_FOLDER.joinpath('.stop').unlink() + break
+ + + +if __name__ == '__main__': # pragma: no cover + # python .\iblrig_tasks\_iblrig_tasks_spontaneous\task.py --subject mysubject + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_spontaneous/task.html b/_modules/iblrig_tasks/_iblrig_tasks_spontaneous/task.html new file mode 100644 index 000000000..0ccc13809 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_spontaneous/task.html @@ -0,0 +1,157 @@ + + + + + + iblrig_tasks._iblrig_tasks_spontaneous.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_spontaneous.task

+"""
+The spontaneous protocol is used to record spontaneous activity in the mouse brain.
+The task does nothing, only creates the architecture for the data streams to be recorded.
+"""
+
+import iblrig.misc
+from iblrig.base_tasks import SpontaneousSession
+
+
+
+[docs] +class Session(SpontaneousSession): + protocol_name = '_iblrig_tasks_spontaneous'
+ + + +if __name__ == '__main__': # pragma: no cover + # python .\iblrig_tasks\_iblrig_tasks_spontaneous\task.py --subject mysubject + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_trainingChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_trainingChoiceWorld/task.html new file mode 100644 index 000000000..93c3df80f --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_trainingChoiceWorld/task.html @@ -0,0 +1,192 @@ + + + + + + iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task

+import iblrig.misc
+from iblrig.base_choice_world import TrainingChoiceWorldSession
+
+TRAINING_PHASE = -1
+ADAPTIVE_REWARD = -1.0
+
+
+
+[docs] +def float_or_none(string: str) -> float | None: + return None if string.lower() == 'none' else float(string)
+ + + +
+[docs] +class Session(TrainingChoiceWorldSession): +
+[docs] + @staticmethod + def extra_parser(): + """:return: argparse.parser()""" + parser = super(Session, Session).extra_parser() + parser.add_argument( + '--training_phase', + option_strings=['--training_phase'], + dest='training_phase', + default=TRAINING_PHASE, + type=int, + help='defines the set of contrasts presented to the subject', + ) + parser.add_argument( + '--adaptive_reward', + option_strings=['--adaptive_reward'], + dest='adaptive_reward', + default=ADAPTIVE_REWARD, + type=float, + help='reward volume in microliters', + ) + parser.add_argument( + '--adaptive_gain', + option_strings=['--adaptive_gain'], + dest='adaptive_gain', + default=None, + type=float_or_none, + help='Gain of the wheel in degrees/mm', + ) + return parser
+
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/iblrig_tasks/_iblrig_tasks_trainingPhaseChoiceWorld/task.html b/_modules/iblrig_tasks/_iblrig_tasks_trainingPhaseChoiceWorld/task.html new file mode 100644 index 000000000..4f9fc7f81 --- /dev/null +++ b/_modules/iblrig_tasks/_iblrig_tasks_trainingPhaseChoiceWorld/task.html @@ -0,0 +1,206 @@ + + + + + + iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task

+from pathlib import Path
+
+import yaml
+
+import iblrig.misc
+from iblrig.base_choice_world import TrainingChoiceWorldSession
+
+# read defaults from task_parameters.yaml
+with open(Path(__file__).parent.joinpath('task_parameters.yaml')) as f:
+    DEFAULTS = yaml.safe_load(f)
+
+
+
+[docs] +class Session(TrainingChoiceWorldSession): + protocol_name = '_iblrig_tasks_trainingPhaseChoiceWorld' + +
+[docs] + def __init__(self, *args, training_level=DEFAULTS['TRAINING_PHASE'], debias=DEFAULTS['DEBIAS'], **kwargs): + super().__init__(*args, training_phase=training_level, **kwargs) + self.task_params['TRAINING_PHASE'] = training_level + self.task_params['DEBIAS'] = debias
+ + +
+[docs] + def check_training_phase(self): + pass
+ + +
+[docs] + @staticmethod + def extra_parser(): + """:return: argparse.parser()""" + parser = super(Session, Session).extra_parser() + parser.add_argument( + '--training_level', + option_strings=['--training_level'], + dest='training_level', + default=DEFAULTS['TRAINING_PHASE'], + type=int, + help='defines the set of contrasts presented to the subject', + ) + parser.add_argument( + '--debias', + option_strings=['--debias'], + dest='debias', + default=DEFAULTS['DEBIAS'], + type=bool, + help='uses the debiasing protocol (only applies to levels 0-4)', + ) + parser.add_argument( + '--adaptive_reward', + option_strings=['--adaptive_reward'], + dest='adaptive_reward', + default=-1.0, + type=float, + help='reward volume in microliters', + ) + return parser
+
+ + + +if __name__ == '__main__': # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 000000000..5c311f70f --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,196 @@ + + + + + + Overview: module code — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ +

All modules for which code is available

+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_sources/api.rst.txt b/_sources/api.rst.txt new file mode 100644 index 000000000..793234776 --- /dev/null +++ b/_sources/api.rst.txt @@ -0,0 +1,10 @@ +API Reference +============= + +.. autosummary:: + :toctree: api + :template: custom-module-template.rst + :recursive: + + iblrig + iblrig_tasks diff --git a/_sources/api/iblrig.base_choice_world.ActiveChoiceWorldSession.rst.txt b/_sources/api/iblrig.base_choice_world.ActiveChoiceWorldSession.rst.txt new file mode 100644 index 000000000..8290d4950 --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.ActiveChoiceWorldSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.ActiveChoiceWorldSession +=================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: ActiveChoiceWorldSession + :parts: 1 + +| + +.. autoclass:: ActiveChoiceWorldSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.rst.txt b/_sources/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.rst.txt new file mode 100644 index 000000000..f07c56d4a --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.ActiveChoiceWorldTrialData +===================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: ActiveChoiceWorldTrialData + :parts: 1 + +| + +.. autoclass:: ActiveChoiceWorldTrialData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.BiasedChoiceWorldSession.rst.txt b/_sources/api/iblrig.base_choice_world.BiasedChoiceWorldSession.rst.txt new file mode 100644 index 000000000..144f123ac --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.BiasedChoiceWorldSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.BiasedChoiceWorldSession +=================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: BiasedChoiceWorldSession + :parts: 1 + +| + +.. autoclass:: BiasedChoiceWorldSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.rst.txt b/_sources/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.rst.txt new file mode 100644 index 000000000..03549eb1f --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.BiasedChoiceWorldTrialData +===================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: BiasedChoiceWorldTrialData + :parts: 1 + +| + +.. autoclass:: BiasedChoiceWorldTrialData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.ChoiceWorldSession.rst.txt b/_sources/api/iblrig.base_choice_world.ChoiceWorldSession.rst.txt new file mode 100644 index 000000000..1234a3450 --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.ChoiceWorldSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.ChoiceWorldSession +============================================= + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: ChoiceWorldSession + :parts: 1 + +| + +.. autoclass:: ChoiceWorldSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.ChoiceWorldTrialData.rst.txt b/_sources/api/iblrig.base_choice_world.ChoiceWorldTrialData.rst.txt new file mode 100644 index 000000000..57ab71268 --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.ChoiceWorldTrialData.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.ChoiceWorldTrialData +=============================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: ChoiceWorldTrialData + :parts: 1 + +| + +.. autoclass:: ChoiceWorldTrialData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.HabituationChoiceWorldSession.rst.txt b/_sources/api/iblrig.base_choice_world.HabituationChoiceWorldSession.rst.txt new file mode 100644 index 000000000..788a74cc9 --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.HabituationChoiceWorldSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.HabituationChoiceWorldSession +======================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: HabituationChoiceWorldSession + :parts: 1 + +| + +.. autoclass:: HabituationChoiceWorldSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.rst.txt b/_sources/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.rst.txt new file mode 100644 index 000000000..cf796e377 --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.HabituationChoiceWorldTrialData +========================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: HabituationChoiceWorldTrialData + :parts: 1 + +| + +.. autoclass:: HabituationChoiceWorldTrialData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.TrainingChoiceWorldSession.rst.txt b/_sources/api/iblrig.base_choice_world.TrainingChoiceWorldSession.rst.txt new file mode 100644 index 000000000..58457799e --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.TrainingChoiceWorldSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.TrainingChoiceWorldSession +===================================================== + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: TrainingChoiceWorldSession + :parts: 1 + +| + +.. autoclass:: TrainingChoiceWorldSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.rst.txt b/_sources/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.rst.txt new file mode 100644 index 000000000..342f1c0cc --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_choice\_world.TrainingChoiceWorldTrialData +======================================================= + +.. currentmodule:: iblrig.base_choice_world + +.. inheritance-diagram:: TrainingChoiceWorldTrialData + :parts: 1 + +| + +.. autoclass:: TrainingChoiceWorldTrialData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_choice_world.rst.txt b/_sources/api/iblrig.base_choice_world.rst.txt new file mode 100644 index 000000000..be8d1f279 --- /dev/null +++ b/_sources/api/iblrig.base_choice_world.rst.txt @@ -0,0 +1,23 @@ +iblrig.base\_choice\_world +========================== + +.. automodule:: iblrig.base_choice_world + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + ActiveChoiceWorldSession + ActiveChoiceWorldTrialData + BiasedChoiceWorldSession + BiasedChoiceWorldTrialData + ChoiceWorldSession + ChoiceWorldTrialData + HabituationChoiceWorldSession + HabituationChoiceWorldTrialData + TrainingChoiceWorldSession + TrainingChoiceWorldTrialData + \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.BaseSession.rst.txt b/_sources/api/iblrig.base_tasks.BaseSession.rst.txt new file mode 100644 index 000000000..bfb434981 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.BaseSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.BaseSession +============================== + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: BaseSession + :parts: 1 + +| + +.. autoclass:: BaseSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.BonsaiRecordingMixin.rst.txt b/_sources/api/iblrig.base_tasks.BonsaiRecordingMixin.rst.txt new file mode 100644 index 000000000..d75302eec --- /dev/null +++ b/_sources/api/iblrig.base_tasks.BonsaiRecordingMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.BonsaiRecordingMixin +======================================= + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: BonsaiRecordingMixin + :parts: 1 + +| + +.. autoclass:: BonsaiRecordingMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.rst.txt b/_sources/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.rst.txt new file mode 100644 index 000000000..ef2270d9d --- /dev/null +++ b/_sources/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.BonsaiVisualStimulusMixin +============================================ + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: BonsaiVisualStimulusMixin + :parts: 1 + +| + +.. autoclass:: BonsaiVisualStimulusMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.BpodMixin.rst.txt b/_sources/api/iblrig.base_tasks.BpodMixin.rst.txt new file mode 100644 index 000000000..56f76b48b --- /dev/null +++ b/_sources/api/iblrig.base_tasks.BpodMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.BpodMixin +============================ + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: BpodMixin + :parts: 1 + +| + +.. autoclass:: BpodMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.EmptySession.rst.txt b/_sources/api/iblrig.base_tasks.EmptySession.rst.txt new file mode 100644 index 000000000..ca3618672 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.EmptySession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.EmptySession +=============================== + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: EmptySession + :parts: 1 + +| + +.. autoclass:: EmptySession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.Frame2TTLMixin.rst.txt b/_sources/api/iblrig.base_tasks.Frame2TTLMixin.rst.txt new file mode 100644 index 000000000..966e02362 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.Frame2TTLMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.Frame2TTLMixin +================================= + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: Frame2TTLMixin + :parts: 1 + +| + +.. autoclass:: Frame2TTLMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.HasBpod.rst.txt b/_sources/api/iblrig.base_tasks.HasBpod.rst.txt new file mode 100644 index 000000000..2ccd90cc9 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.HasBpod.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.HasBpod +========================== + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: HasBpod + :parts: 1 + +| + +.. autoclass:: HasBpod + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.NetworkSession.rst.txt b/_sources/api/iblrig.base_tasks.NetworkSession.rst.txt new file mode 100644 index 000000000..dccc9792c --- /dev/null +++ b/_sources/api/iblrig.base_tasks.NetworkSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.NetworkSession +================================= + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: NetworkSession + :parts: 1 + +| + +.. autoclass:: NetworkSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.OSCClient.rst.txt b/_sources/api/iblrig.base_tasks.OSCClient.rst.txt new file mode 100644 index 000000000..8fd0ea165 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.OSCClient.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.OSCClient +============================ + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: OSCClient + :parts: 1 + +| + +.. autoclass:: OSCClient + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.RotaryEncoderMixin.rst.txt b/_sources/api/iblrig.base_tasks.RotaryEncoderMixin.rst.txt new file mode 100644 index 000000000..c6383f993 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.RotaryEncoderMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.RotaryEncoderMixin +===================================== + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: RotaryEncoderMixin + :parts: 1 + +| + +.. autoclass:: RotaryEncoderMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.SoundMixin.rst.txt b/_sources/api/iblrig.base_tasks.SoundMixin.rst.txt new file mode 100644 index 000000000..7254128f5 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.SoundMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.SoundMixin +============================= + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: SoundMixin + :parts: 1 + +| + +.. autoclass:: SoundMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.SpontaneousSession.rst.txt b/_sources/api/iblrig.base_tasks.SpontaneousSession.rst.txt new file mode 100644 index 000000000..715da2ee2 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.SpontaneousSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.SpontaneousSession +===================================== + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: SpontaneousSession + :parts: 1 + +| + +.. autoclass:: SpontaneousSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.ValveMixin.rst.txt b/_sources/api/iblrig.base_tasks.ValveMixin.rst.txt new file mode 100644 index 000000000..de8a1351f --- /dev/null +++ b/_sources/api/iblrig.base_tasks.ValveMixin.rst.txt @@ -0,0 +1,13 @@ +iblrig.base\_tasks.ValveMixin +============================= + +.. currentmodule:: iblrig.base_tasks + +.. inheritance-diagram:: ValveMixin + :parts: 1 + +| + +.. autoclass:: ValveMixin + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.base_tasks.rst.txt b/_sources/api/iblrig.base_tasks.rst.txt new file mode 100644 index 000000000..e3acf52e7 --- /dev/null +++ b/_sources/api/iblrig.base_tasks.rst.txt @@ -0,0 +1,26 @@ +iblrig.base\_tasks +================== + +.. automodule:: iblrig.base_tasks + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + BaseSession + BonsaiRecordingMixin + BonsaiVisualStimulusMixin + BpodMixin + EmptySession + Frame2TTLMixin + HasBpod + NetworkSession + OSCClient + RotaryEncoderMixin + SoundMixin + SpontaneousSession + ValveMixin + \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.compute_adaptive_reward_volume.rst.txt b/_sources/api/iblrig.choiceworld.compute_adaptive_reward_volume.rst.txt new file mode 100644 index 000000000..0158cbf79 --- /dev/null +++ b/_sources/api/iblrig.choiceworld.compute_adaptive_reward_volume.rst.txt @@ -0,0 +1,6 @@ +iblrig.choiceworld.compute\_adaptive\_reward\_volume +==================================================== + +.. currentmodule:: iblrig.choiceworld + +.. autofunction:: compute_adaptive_reward_volume \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.contrasts_set.rst.txt b/_sources/api/iblrig.choiceworld.contrasts_set.rst.txt new file mode 100644 index 000000000..b29eed443 --- /dev/null +++ b/_sources/api/iblrig.choiceworld.contrasts_set.rst.txt @@ -0,0 +1,6 @@ +iblrig.choiceworld.contrasts\_set +================================= + +.. currentmodule:: iblrig.choiceworld + +.. autofunction:: contrasts_set \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.draw_training_contrast.rst.txt b/_sources/api/iblrig.choiceworld.draw_training_contrast.rst.txt new file mode 100644 index 000000000..288bcc122 --- /dev/null +++ b/_sources/api/iblrig.choiceworld.draw_training_contrast.rst.txt @@ -0,0 +1,6 @@ +iblrig.choiceworld.draw\_training\_contrast +=========================================== + +.. currentmodule:: iblrig.choiceworld + +.. autofunction:: draw_training_contrast \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.get_subject_training_info.rst.txt b/_sources/api/iblrig.choiceworld.get_subject_training_info.rst.txt new file mode 100644 index 000000000..c9dccd9fa --- /dev/null +++ b/_sources/api/iblrig.choiceworld.get_subject_training_info.rst.txt @@ -0,0 +1,6 @@ +iblrig.choiceworld.get\_subject\_training\_info +=============================================== + +.. currentmodule:: iblrig.choiceworld + +.. autofunction:: get_subject_training_info \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.rst.txt b/_sources/api/iblrig.choiceworld.rst.txt new file mode 100644 index 000000000..3761c3f97 --- /dev/null +++ b/_sources/api/iblrig.choiceworld.rst.txt @@ -0,0 +1,18 @@ +iblrig.choiceworld +================== + +.. automodule:: iblrig.choiceworld + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + compute_adaptive_reward_volume + contrasts_set + draw_training_contrast + get_subject_training_info + training_contrasts_probabilities + training_phase_from_contrast_set + \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.training_contrasts_probabilities.rst.txt b/_sources/api/iblrig.choiceworld.training_contrasts_probabilities.rst.txt new file mode 100644 index 000000000..17cc68685 --- /dev/null +++ b/_sources/api/iblrig.choiceworld.training_contrasts_probabilities.rst.txt @@ -0,0 +1,6 @@ +iblrig.choiceworld.training\_contrasts\_probabilities +===================================================== + +.. currentmodule:: iblrig.choiceworld + +.. autofunction:: training_contrasts_probabilities \ No newline at end of file diff --git a/_sources/api/iblrig.choiceworld.training_phase_from_contrast_set.rst.txt b/_sources/api/iblrig.choiceworld.training_phase_from_contrast_set.rst.txt new file mode 100644 index 000000000..f8e415b95 --- /dev/null +++ b/_sources/api/iblrig.choiceworld.training_phase_from_contrast_set.rst.txt @@ -0,0 +1,6 @@ +iblrig.choiceworld.training\_phase\_from\_contrast\_set +======================================================= + +.. currentmodule:: iblrig.choiceworld + +.. autofunction:: training_phase_from_contrast_set \ No newline at end of file diff --git a/_sources/api/iblrig.commands.dir_path.rst.txt b/_sources/api/iblrig.commands.dir_path.rst.txt new file mode 100644 index 000000000..ee83c6979 --- /dev/null +++ b/_sources/api/iblrig.commands.dir_path.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.dir\_path +========================= + +.. currentmodule:: iblrig.commands + +.. autofunction:: dir_path \ No newline at end of file diff --git a/_sources/api/iblrig.commands.flush.rst.txt b/_sources/api/iblrig.commands.flush.rst.txt new file mode 100644 index 000000000..65042ab35 --- /dev/null +++ b/_sources/api/iblrig.commands.flush.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.flush +===================== + +.. currentmodule:: iblrig.commands + +.. autofunction:: flush \ No newline at end of file diff --git a/_sources/api/iblrig.commands.remove_local_sessions.rst.txt b/_sources/api/iblrig.commands.remove_local_sessions.rst.txt new file mode 100644 index 000000000..ba783859f --- /dev/null +++ b/_sources/api/iblrig.commands.remove_local_sessions.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.remove\_local\_sessions +======================================= + +.. currentmodule:: iblrig.commands + +.. autofunction:: remove_local_sessions \ No newline at end of file diff --git a/_sources/api/iblrig.commands.rst.txt b/_sources/api/iblrig.commands.rst.txt new file mode 100644 index 000000000..0a866eaf6 --- /dev/null +++ b/_sources/api/iblrig.commands.rst.txt @@ -0,0 +1,20 @@ +iblrig.commands +=============== + +.. automodule:: iblrig.commands + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + dir_path + flush + remove_local_sessions + transfer_data + transfer_data_cli + transfer_ephys_data_cli + transfer_video_data_cli + view_session + \ No newline at end of file diff --git a/_sources/api/iblrig.commands.transfer_data.rst.txt b/_sources/api/iblrig.commands.transfer_data.rst.txt new file mode 100644 index 000000000..5ad02559f --- /dev/null +++ b/_sources/api/iblrig.commands.transfer_data.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.transfer\_data +============================== + +.. currentmodule:: iblrig.commands + +.. autofunction:: transfer_data \ No newline at end of file diff --git a/_sources/api/iblrig.commands.transfer_data_cli.rst.txt b/_sources/api/iblrig.commands.transfer_data_cli.rst.txt new file mode 100644 index 000000000..7b9199dce --- /dev/null +++ b/_sources/api/iblrig.commands.transfer_data_cli.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.transfer\_data\_cli +=================================== + +.. currentmodule:: iblrig.commands + +.. autofunction:: transfer_data_cli \ No newline at end of file diff --git a/_sources/api/iblrig.commands.transfer_ephys_data_cli.rst.txt b/_sources/api/iblrig.commands.transfer_ephys_data_cli.rst.txt new file mode 100644 index 000000000..4b5a995c7 --- /dev/null +++ b/_sources/api/iblrig.commands.transfer_ephys_data_cli.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.transfer\_ephys\_data\_cli +========================================== + +.. currentmodule:: iblrig.commands + +.. autofunction:: transfer_ephys_data_cli \ No newline at end of file diff --git a/_sources/api/iblrig.commands.transfer_video_data_cli.rst.txt b/_sources/api/iblrig.commands.transfer_video_data_cli.rst.txt new file mode 100644 index 000000000..ee388826e --- /dev/null +++ b/_sources/api/iblrig.commands.transfer_video_data_cli.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.transfer\_video\_data\_cli +========================================== + +.. currentmodule:: iblrig.commands + +.. autofunction:: transfer_video_data_cli \ No newline at end of file diff --git a/_sources/api/iblrig.commands.view_session.rst.txt b/_sources/api/iblrig.commands.view_session.rst.txt new file mode 100644 index 000000000..225dc044d --- /dev/null +++ b/_sources/api/iblrig.commands.view_session.rst.txt @@ -0,0 +1,6 @@ +iblrig.commands.view\_session +============================= + +.. currentmodule:: iblrig.commands + +.. autofunction:: view_session \ No newline at end of file diff --git a/_sources/api/iblrig.constants.rst.txt b/_sources/api/iblrig.constants.rst.txt new file mode 100644 index 000000000..c3cfc7f95 --- /dev/null +++ b/_sources/api/iblrig.constants.rst.txt @@ -0,0 +1,5 @@ +iblrig.constants +================ + +.. automodule:: iblrig.constants + \ No newline at end of file diff --git a/_sources/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.rst.txt b/_sources/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.rst.txt new file mode 100644 index 000000000..42eb373fd --- /dev/null +++ b/_sources/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.rst.txt @@ -0,0 +1,6 @@ +iblrig.ephys.neuropixel24\_micromanipulator\_coordinates +======================================================== + +.. currentmodule:: iblrig.ephys + +.. autofunction:: neuropixel24_micromanipulator_coordinates \ No newline at end of file diff --git a/_sources/api/iblrig.ephys.prepare_ephys_session.rst.txt b/_sources/api/iblrig.ephys.prepare_ephys_session.rst.txt new file mode 100644 index 000000000..9e58eb5bd --- /dev/null +++ b/_sources/api/iblrig.ephys.prepare_ephys_session.rst.txt @@ -0,0 +1,6 @@ +iblrig.ephys.prepare\_ephys\_session +==================================== + +.. currentmodule:: iblrig.ephys + +.. autofunction:: prepare_ephys_session \ No newline at end of file diff --git a/_sources/api/iblrig.ephys.prepare_ephys_session_cmd.rst.txt b/_sources/api/iblrig.ephys.prepare_ephys_session_cmd.rst.txt new file mode 100644 index 000000000..4ab53164e --- /dev/null +++ b/_sources/api/iblrig.ephys.prepare_ephys_session_cmd.rst.txt @@ -0,0 +1,6 @@ +iblrig.ephys.prepare\_ephys\_session\_cmd +========================================= + +.. currentmodule:: iblrig.ephys + +.. autofunction:: prepare_ephys_session_cmd \ No newline at end of file diff --git a/_sources/api/iblrig.ephys.rst.txt b/_sources/api/iblrig.ephys.rst.txt new file mode 100644 index 000000000..a159866db --- /dev/null +++ b/_sources/api/iblrig.ephys.rst.txt @@ -0,0 +1,15 @@ +iblrig.ephys +============ + +.. automodule:: iblrig.ephys + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + neuropixel24_micromanipulator_coordinates + prepare_ephys_session + prepare_ephys_session_cmd + \ No newline at end of file diff --git a/_sources/api/iblrig.frame2ttl.Frame2TTL.rst.txt b/_sources/api/iblrig.frame2ttl.Frame2TTL.rst.txt new file mode 100644 index 000000000..f8b83830d --- /dev/null +++ b/_sources/api/iblrig.frame2ttl.Frame2TTL.rst.txt @@ -0,0 +1,13 @@ +iblrig.frame2ttl.Frame2TTL +========================== + +.. currentmodule:: iblrig.frame2ttl + +.. inheritance-diagram:: Frame2TTL + :parts: 1 + +| + +.. autoclass:: Frame2TTL + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.frame2ttl.rst.txt b/_sources/api/iblrig.frame2ttl.rst.txt new file mode 100644 index 000000000..c47f614ee --- /dev/null +++ b/_sources/api/iblrig.frame2ttl.rst.txt @@ -0,0 +1,14 @@ +iblrig.frame2ttl +================ + +.. automodule:: iblrig.frame2ttl + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Frame2TTL + \ No newline at end of file diff --git a/_sources/api/iblrig.graphic.numinput.rst.txt b/_sources/api/iblrig.graphic.numinput.rst.txt new file mode 100644 index 000000000..6db722a73 --- /dev/null +++ b/_sources/api/iblrig.graphic.numinput.rst.txt @@ -0,0 +1,6 @@ +iblrig.graphic.numinput +======================= + +.. currentmodule:: iblrig.graphic + +.. autofunction:: numinput \ No newline at end of file diff --git a/_sources/api/iblrig.graphic.rst.txt b/_sources/api/iblrig.graphic.rst.txt new file mode 100644 index 000000000..d35d52f3e --- /dev/null +++ b/_sources/api/iblrig.graphic.rst.txt @@ -0,0 +1,13 @@ +iblrig.graphic +============== + +.. automodule:: iblrig.graphic + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + numinput + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.rst.txt b/_sources/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.rst.txt new file mode 100644 index 000000000..e995662e5 --- /dev/null +++ b/_sources/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog +=============================================== + +.. currentmodule:: iblrig.gui.frame2ttl + +.. inheritance-diagram:: Frame2TTLCalibrationDialog + :parts: 1 + +| + +.. autoclass:: Frame2TTLCalibrationDialog + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.rst.txt b/_sources/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.rst.txt new file mode 100644 index 000000000..57bc24a2b --- /dev/null +++ b/_sources/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget +=============================================== + +.. currentmodule:: iblrig.gui.frame2ttl + +.. inheritance-diagram:: Frame2TTLCalibrationTarget + :parts: 1 + +| + +.. autoclass:: Frame2TTLCalibrationTarget + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.frame2ttl.rst.txt b/_sources/api/iblrig.gui.frame2ttl.rst.txt new file mode 100644 index 000000000..7363cdc61 --- /dev/null +++ b/_sources/api/iblrig.gui.frame2ttl.rst.txt @@ -0,0 +1,15 @@ +iblrig.gui.frame2ttl +==================== + +.. automodule:: iblrig.gui.frame2ttl + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Frame2TTLCalibrationDialog + Frame2TTLCalibrationTarget + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.resources_rc.qCleanupResources.rst.txt b/_sources/api/iblrig.gui.resources_rc.qCleanupResources.rst.txt new file mode 100644 index 000000000..eb24a9726 --- /dev/null +++ b/_sources/api/iblrig.gui.resources_rc.qCleanupResources.rst.txt @@ -0,0 +1,6 @@ +iblrig.gui.resources\_rc.qCleanupResources +========================================== + +.. currentmodule:: iblrig.gui.resources_rc + +.. autofunction:: qCleanupResources \ No newline at end of file diff --git a/_sources/api/iblrig.gui.resources_rc.qInitResources.rst.txt b/_sources/api/iblrig.gui.resources_rc.qInitResources.rst.txt new file mode 100644 index 000000000..12c83bb50 --- /dev/null +++ b/_sources/api/iblrig.gui.resources_rc.qInitResources.rst.txt @@ -0,0 +1,6 @@ +iblrig.gui.resources\_rc.qInitResources +======================================= + +.. currentmodule:: iblrig.gui.resources_rc + +.. autofunction:: qInitResources \ No newline at end of file diff --git a/_sources/api/iblrig.gui.resources_rc.rst.txt b/_sources/api/iblrig.gui.resources_rc.rst.txt new file mode 100644 index 000000000..432785387 --- /dev/null +++ b/_sources/api/iblrig.gui.resources_rc.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.resources\_rc +======================== + +.. automodule:: iblrig.gui.resources_rc + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + qCleanupResources + qInitResources + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.rst.txt b/_sources/api/iblrig.gui.rst.txt new file mode 100644 index 000000000..03c96cdea --- /dev/null +++ b/_sources/api/iblrig.gui.rst.txt @@ -0,0 +1,63 @@ +iblrig.gui +========== + +.. automodule:: iblrig.gui + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + frame2ttl + + micromanipulator + + resources_rc + + splash + + tab_about + + tab_data + + tab_docs + + tab_log + + tools + + ui_frame2ttl + + ui_login + + ui_micromanipulator + + ui_splash + + ui_tab_about + + ui_tab_data + + ui_tab_docs + + ui_tab_log + + ui_tab_session + + ui_update + + ui_validation + + ui_valve + + ui_wizard + + validation + + valve + + wizard + diff --git a/_sources/api/iblrig.gui.splash.Splash.rst.txt b/_sources/api/iblrig.gui.splash.Splash.rst.txt new file mode 100644 index 000000000..18a687861 --- /dev/null +++ b/_sources/api/iblrig.gui.splash.Splash.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.splash.Splash +======================== + +.. currentmodule:: iblrig.gui.splash + +.. inheritance-diagram:: Splash + :parts: 1 + +| + +.. autoclass:: Splash + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.splash.rst.txt b/_sources/api/iblrig.gui.splash.rst.txt new file mode 100644 index 000000000..7e016582b --- /dev/null +++ b/_sources/api/iblrig.gui.splash.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.splash +================= + +.. automodule:: iblrig.gui.splash + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Splash + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_about.TabAbout.rst.txt b/_sources/api/iblrig.gui.tab_about.TabAbout.rst.txt new file mode 100644 index 000000000..c3730bdf6 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_about.TabAbout.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_about.TabAbout +============================== + +.. currentmodule:: iblrig.gui.tab_about + +.. inheritance-diagram:: TabAbout + :parts: 1 + +| + +.. autoclass:: TabAbout + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_about.rst.txt b/_sources/api/iblrig.gui.tab_about.rst.txt new file mode 100644 index 000000000..756917726 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_about.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.tab\_about +===================== + +.. automodule:: iblrig.gui.tab_about + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + TabAbout + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_data.Column.rst.txt b/_sources/api/iblrig.gui.tab_data.Column.rst.txt new file mode 100644 index 000000000..bdb701ce7 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_data.Column.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_data.Column +=========================== + +.. currentmodule:: iblrig.gui.tab_data + +.. inheritance-diagram:: Column + :parts: 1 + +| + +.. autoclass:: Column + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_data.DataItemDelegate.rst.txt b/_sources/api/iblrig.gui.tab_data.DataItemDelegate.rst.txt new file mode 100644 index 000000000..fc10cf34b --- /dev/null +++ b/_sources/api/iblrig.gui.tab_data.DataItemDelegate.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_data.DataItemDelegate +===================================== + +.. currentmodule:: iblrig.gui.tab_data + +.. inheritance-diagram:: DataItemDelegate + :parts: 1 + +| + +.. autoclass:: DataItemDelegate + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_data.DataWorker.rst.txt b/_sources/api/iblrig.gui.tab_data.DataWorker.rst.txt new file mode 100644 index 000000000..3e15d8eca --- /dev/null +++ b/_sources/api/iblrig.gui.tab_data.DataWorker.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_data.DataWorker +=============================== + +.. currentmodule:: iblrig.gui.tab_data + +.. inheritance-diagram:: DataWorker + :parts: 1 + +| + +.. autoclass:: DataWorker + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_data.TabData.rst.txt b/_sources/api/iblrig.gui.tab_data.TabData.rst.txt new file mode 100644 index 000000000..762501932 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_data.TabData.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_data.TabData +============================ + +.. currentmodule:: iblrig.gui.tab_data + +.. inheritance-diagram:: TabData + :parts: 1 + +| + +.. autoclass:: TabData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_data.rst.txt b/_sources/api/iblrig.gui.tab_data.rst.txt new file mode 100644 index 000000000..dab3c1afe --- /dev/null +++ b/_sources/api/iblrig.gui.tab_data.rst.txt @@ -0,0 +1,25 @@ +iblrig.gui.tab\_data +==================== + +.. automodule:: iblrig.gui.tab_data + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + sizeof_fmt + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Column + DataItemDelegate + DataWorker + TabData + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_data.sizeof_fmt.rst.txt b/_sources/api/iblrig.gui.tab_data.sizeof_fmt.rst.txt new file mode 100644 index 000000000..3e5cfedd2 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_data.sizeof_fmt.rst.txt @@ -0,0 +1,6 @@ +iblrig.gui.tab\_data.sizeof\_fmt +================================ + +.. currentmodule:: iblrig.gui.tab_data + +.. autofunction:: sizeof_fmt \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_docs.CustomWebEnginePage.rst.txt b/_sources/api/iblrig.gui.tab_docs.CustomWebEnginePage.rst.txt new file mode 100644 index 000000000..c7627617c --- /dev/null +++ b/_sources/api/iblrig.gui.tab_docs.CustomWebEnginePage.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_docs.CustomWebEnginePage +======================================== + +.. currentmodule:: iblrig.gui.tab_docs + +.. inheritance-diagram:: CustomWebEnginePage + :parts: 1 + +| + +.. autoclass:: CustomWebEnginePage + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_docs.TabDocs.rst.txt b/_sources/api/iblrig.gui.tab_docs.TabDocs.rst.txt new file mode 100644 index 000000000..46565662e --- /dev/null +++ b/_sources/api/iblrig.gui.tab_docs.TabDocs.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_docs.TabDocs +============================ + +.. currentmodule:: iblrig.gui.tab_docs + +.. inheritance-diagram:: TabDocs + :parts: 1 + +| + +.. autoclass:: TabDocs + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_docs.rst.txt b/_sources/api/iblrig.gui.tab_docs.rst.txt new file mode 100644 index 000000000..9d63bed53 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_docs.rst.txt @@ -0,0 +1,15 @@ +iblrig.gui.tab\_docs +==================== + +.. automodule:: iblrig.gui.tab_docs + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + CustomWebEnginePage + TabDocs + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_log.TabLog.rst.txt b/_sources/api/iblrig.gui.tab_log.TabLog.rst.txt new file mode 100644 index 000000000..e61510ad4 --- /dev/null +++ b/_sources/api/iblrig.gui.tab_log.TabLog.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tab\_log.TabLog +========================== + +.. currentmodule:: iblrig.gui.tab_log + +.. inheritance-diagram:: TabLog + :parts: 1 + +| + +.. autoclass:: TabLog + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tab_log.rst.txt b/_sources/api/iblrig.gui.tab_log.rst.txt new file mode 100644 index 000000000..8fb38c89e --- /dev/null +++ b/_sources/api/iblrig.gui.tab_log.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.tab\_log +=================== + +.. automodule:: iblrig.gui.tab_log + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + TabLog + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.AlyxObject.rst.txt b/_sources/api/iblrig.gui.tools.AlyxObject.rst.txt new file mode 100644 index 000000000..e157c7484 --- /dev/null +++ b/_sources/api/iblrig.gui.tools.AlyxObject.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.AlyxObject +=========================== + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: AlyxObject + :parts: 1 + +| + +.. autoclass:: AlyxObject + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.DataFrameTableModel.rst.txt b/_sources/api/iblrig.gui.tools.DataFrameTableModel.rst.txt new file mode 100644 index 000000000..ea81d818d --- /dev/null +++ b/_sources/api/iblrig.gui.tools.DataFrameTableModel.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.DataFrameTableModel +==================================== + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: DataFrameTableModel + :parts: 1 + +| + +.. autoclass:: DataFrameTableModel + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.DiskSpaceIndicator.rst.txt b/_sources/api/iblrig.gui.tools.DiskSpaceIndicator.rst.txt new file mode 100644 index 000000000..9cce9012d --- /dev/null +++ b/_sources/api/iblrig.gui.tools.DiskSpaceIndicator.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.DiskSpaceIndicator +=================================== + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: DiskSpaceIndicator + :parts: 1 + +| + +.. autoclass:: DiskSpaceIndicator + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.LineEditAlyxUser.rst.txt b/_sources/api/iblrig.gui.tools.LineEditAlyxUser.rst.txt new file mode 100644 index 000000000..48cd2415f --- /dev/null +++ b/_sources/api/iblrig.gui.tools.LineEditAlyxUser.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.LineEditAlyxUser +================================= + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: LineEditAlyxUser + :parts: 1 + +| + +.. autoclass:: LineEditAlyxUser + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.RemoteDevicesItemModel.rst.txt b/_sources/api/iblrig.gui.tools.RemoteDevicesItemModel.rst.txt new file mode 100644 index 000000000..567af7f34 --- /dev/null +++ b/_sources/api/iblrig.gui.tools.RemoteDevicesItemModel.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.RemoteDevicesItemModel +======================================= + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: RemoteDevicesItemModel + :parts: 1 + +| + +.. autoclass:: RemoteDevicesItemModel + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.RemoteDevicesListView.rst.txt b/_sources/api/iblrig.gui.tools.RemoteDevicesListView.rst.txt new file mode 100644 index 000000000..3c15e7485 --- /dev/null +++ b/_sources/api/iblrig.gui.tools.RemoteDevicesListView.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.RemoteDevicesListView +====================================== + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: RemoteDevicesListView + :parts: 1 + +| + +.. autoclass:: RemoteDevicesListView + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.StatefulButton.rst.txt b/_sources/api/iblrig.gui.tools.StatefulButton.rst.txt new file mode 100644 index 000000000..7accffacf --- /dev/null +++ b/_sources/api/iblrig.gui.tools.StatefulButton.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.StatefulButton +=============================== + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: StatefulButton + :parts: 1 + +| + +.. autoclass:: StatefulButton + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.Worker.rst.txt b/_sources/api/iblrig.gui.tools.Worker.rst.txt new file mode 100644 index 000000000..12c670994 --- /dev/null +++ b/_sources/api/iblrig.gui.tools.Worker.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.Worker +======================= + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: Worker + :parts: 1 + +| + +.. autoclass:: Worker + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.WorkerSignals.rst.txt b/_sources/api/iblrig.gui.tools.WorkerSignals.rst.txt new file mode 100644 index 000000000..85e8a60d7 --- /dev/null +++ b/_sources/api/iblrig.gui.tools.WorkerSignals.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.tools.WorkerSignals +============================== + +.. currentmodule:: iblrig.gui.tools + +.. inheritance-diagram:: WorkerSignals + :parts: 1 + +| + +.. autoclass:: WorkerSignals + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.convert_uis.rst.txt b/_sources/api/iblrig.gui.tools.convert_uis.rst.txt new file mode 100644 index 000000000..959c9a46a --- /dev/null +++ b/_sources/api/iblrig.gui.tools.convert_uis.rst.txt @@ -0,0 +1,6 @@ +iblrig.gui.tools.convert\_uis +============================= + +.. currentmodule:: iblrig.gui.tools + +.. autofunction:: convert_uis \ No newline at end of file diff --git a/_sources/api/iblrig.gui.tools.rst.txt b/_sources/api/iblrig.gui.tools.rst.txt new file mode 100644 index 000000000..5a12f17b2 --- /dev/null +++ b/_sources/api/iblrig.gui.tools.rst.txt @@ -0,0 +1,30 @@ +iblrig.gui.tools +================ + +.. automodule:: iblrig.gui.tools + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + convert_uis + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + AlyxObject + DataFrameTableModel + DiskSpaceIndicator + LineEditAlyxUser + RemoteDevicesItemModel + RemoteDevicesListView + StatefulButton + Worker + WorkerSignals + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.rst.txt b/_sources/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.rst.txt new file mode 100644 index 000000000..7af0df468 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_frame2ttl.Ui\_frame2ttl +====================================== + +.. currentmodule:: iblrig.gui.ui_frame2ttl + +.. inheritance-diagram:: Ui_frame2ttl + :parts: 1 + +| + +.. autoclass:: Ui_frame2ttl + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_frame2ttl.rst.txt b/_sources/api/iblrig.gui.ui_frame2ttl.rst.txt new file mode 100644 index 000000000..bb9397c73 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_frame2ttl.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_frame2ttl +======================== + +.. automodule:: iblrig.gui.ui_frame2ttl + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_frame2ttl + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_login.Ui_login.rst.txt b/_sources/api/iblrig.gui.ui_login.Ui_login.rst.txt new file mode 100644 index 000000000..c5abfcbf0 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_login.Ui_login.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_login.Ui\_login +============================== + +.. currentmodule:: iblrig.gui.ui_login + +.. inheritance-diagram:: Ui_login + :parts: 1 + +| + +.. autoclass:: Ui_login + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_login.rst.txt b/_sources/api/iblrig.gui.ui_login.rst.txt new file mode 100644 index 000000000..cc8972c9c --- /dev/null +++ b/_sources/api/iblrig.gui.ui_login.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_login +==================== + +.. automodule:: iblrig.gui.ui_login + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_login + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_splash.Ui_splash.rst.txt b/_sources/api/iblrig.gui.ui_splash.Ui_splash.rst.txt new file mode 100644 index 000000000..1481a2c52 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_splash.Ui_splash.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_splash.Ui\_splash +================================ + +.. currentmodule:: iblrig.gui.ui_splash + +.. inheritance-diagram:: Ui_splash + :parts: 1 + +| + +.. autoclass:: Ui_splash + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_splash.rst.txt b/_sources/api/iblrig.gui.ui_splash.rst.txt new file mode 100644 index 000000000..66301d725 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_splash.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_splash +===================== + +.. automodule:: iblrig.gui.ui_splash + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_splash + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_about.Ui_TabAbout.rst.txt b/_sources/api/iblrig.gui.ui_tab_about.Ui_TabAbout.rst.txt new file mode 100644 index 000000000..ee5184af4 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_about.Ui_TabAbout.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_tab\_about.Ui\_TabAbout +====================================== + +.. currentmodule:: iblrig.gui.ui_tab_about + +.. inheritance-diagram:: Ui_TabAbout + :parts: 1 + +| + +.. autoclass:: Ui_TabAbout + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_about.rst.txt b/_sources/api/iblrig.gui.ui_tab_about.rst.txt new file mode 100644 index 000000000..59fbf6848 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_about.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_tab\_about +========================= + +.. automodule:: iblrig.gui.ui_tab_about + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_TabAbout + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_data.Ui_TabData.rst.txt b/_sources/api/iblrig.gui.ui_tab_data.Ui_TabData.rst.txt new file mode 100644 index 000000000..6269e78d0 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_data.Ui_TabData.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_tab\_data.Ui\_TabData +==================================== + +.. currentmodule:: iblrig.gui.ui_tab_data + +.. inheritance-diagram:: Ui_TabData + :parts: 1 + +| + +.. autoclass:: Ui_TabData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_data.rst.txt b/_sources/api/iblrig.gui.ui_tab_data.rst.txt new file mode 100644 index 000000000..7596e4baa --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_data.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_tab\_data +======================== + +.. automodule:: iblrig.gui.ui_tab_data + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_TabData + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.rst.txt b/_sources/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.rst.txt new file mode 100644 index 000000000..658ac2395 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_tab\_docs.Ui\_TabDocs +==================================== + +.. currentmodule:: iblrig.gui.ui_tab_docs + +.. inheritance-diagram:: Ui_TabDocs + :parts: 1 + +| + +.. autoclass:: Ui_TabDocs + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_docs.rst.txt b/_sources/api/iblrig.gui.ui_tab_docs.rst.txt new file mode 100644 index 000000000..0f36764b8 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_docs.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_tab\_docs +======================== + +.. automodule:: iblrig.gui.ui_tab_docs + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_TabDocs + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_log.Ui_TabLog.rst.txt b/_sources/api/iblrig.gui.ui_tab_log.Ui_TabLog.rst.txt new file mode 100644 index 000000000..b425f8ce1 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_log.Ui_TabLog.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_tab\_log.Ui\_TabLog +================================== + +.. currentmodule:: iblrig.gui.ui_tab_log + +.. inheritance-diagram:: Ui_TabLog + :parts: 1 + +| + +.. autoclass:: Ui_TabLog + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_log.rst.txt b/_sources/api/iblrig.gui.ui_tab_log.rst.txt new file mode 100644 index 000000000..d98ce584c --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_log.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_tab\_log +======================= + +.. automodule:: iblrig.gui.ui_tab_log + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_TabLog + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_session.Ui_tabSession.rst.txt b/_sources/api/iblrig.gui.ui_tab_session.Ui_tabSession.rst.txt new file mode 100644 index 000000000..6ef1503ef --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_session.Ui_tabSession.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_tab\_session.Ui\_tabSession +========================================== + +.. currentmodule:: iblrig.gui.ui_tab_session + +.. inheritance-diagram:: Ui_tabSession + :parts: 1 + +| + +.. autoclass:: Ui_tabSession + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_tab_session.rst.txt b/_sources/api/iblrig.gui.ui_tab_session.rst.txt new file mode 100644 index 000000000..7c62a915b --- /dev/null +++ b/_sources/api/iblrig.gui.ui_tab_session.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_tab\_session +=========================== + +.. automodule:: iblrig.gui.ui_tab_session + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_tabSession + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_update.Ui_update.rst.txt b/_sources/api/iblrig.gui.ui_update.Ui_update.rst.txt new file mode 100644 index 000000000..f06bc08d3 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_update.Ui_update.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_update.Ui\_update +================================ + +.. currentmodule:: iblrig.gui.ui_update + +.. inheritance-diagram:: Ui_update + :parts: 1 + +| + +.. autoclass:: Ui_update + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_update.rst.txt b/_sources/api/iblrig.gui.ui_update.rst.txt new file mode 100644 index 000000000..99af057e6 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_update.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_update +===================== + +.. automodule:: iblrig.gui.ui_update + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_update + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_validation.Ui_validation.rst.txt b/_sources/api/iblrig.gui.ui_validation.Ui_validation.rst.txt new file mode 100644 index 000000000..c7950af04 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_validation.Ui_validation.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_validation.Ui\_validation +======================================== + +.. currentmodule:: iblrig.gui.ui_validation + +.. inheritance-diagram:: Ui_validation + :parts: 1 + +| + +.. autoclass:: Ui_validation + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_validation.rst.txt b/_sources/api/iblrig.gui.ui_validation.rst.txt new file mode 100644 index 000000000..26498fe02 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_validation.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_validation +========================= + +.. automodule:: iblrig.gui.ui_validation + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_validation + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_valve.Ui_valve.rst.txt b/_sources/api/iblrig.gui.ui_valve.Ui_valve.rst.txt new file mode 100644 index 000000000..d323937ca --- /dev/null +++ b/_sources/api/iblrig.gui.ui_valve.Ui_valve.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_valve.Ui\_valve +============================== + +.. currentmodule:: iblrig.gui.ui_valve + +.. inheritance-diagram:: Ui_valve + :parts: 1 + +| + +.. autoclass:: Ui_valve + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_valve.rst.txt b/_sources/api/iblrig.gui.ui_valve.rst.txt new file mode 100644 index 000000000..22750a272 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_valve.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_valve +==================== + +.. automodule:: iblrig.gui.ui_valve + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_valve + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_wizard.Ui_wizard.rst.txt b/_sources/api/iblrig.gui.ui_wizard.Ui_wizard.rst.txt new file mode 100644 index 000000000..af6eec3b9 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_wizard.Ui_wizard.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.ui\_wizard.Ui\_wizard +================================ + +.. currentmodule:: iblrig.gui.ui_wizard + +.. inheritance-diagram:: Ui_wizard + :parts: 1 + +| + +.. autoclass:: Ui_wizard + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.ui_wizard.rst.txt b/_sources/api/iblrig.gui.ui_wizard.rst.txt new file mode 100644 index 000000000..2214de505 --- /dev/null +++ b/_sources/api/iblrig.gui.ui_wizard.rst.txt @@ -0,0 +1,14 @@ +iblrig.gui.ui\_wizard +===================== + +.. automodule:: iblrig.gui.ui_wizard + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Ui_wizard + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.validation.StatusItem.rst.txt b/_sources/api/iblrig.gui.validation.StatusItem.rst.txt new file mode 100644 index 000000000..5ee3f0b01 --- /dev/null +++ b/_sources/api/iblrig.gui.validation.StatusItem.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.validation.StatusItem +================================ + +.. currentmodule:: iblrig.gui.validation + +.. inheritance-diagram:: StatusItem + :parts: 1 + +| + +.. autoclass:: StatusItem + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.validation.SystemValidationDialog.rst.txt b/_sources/api/iblrig.gui.validation.SystemValidationDialog.rst.txt new file mode 100644 index 000000000..95267d534 --- /dev/null +++ b/_sources/api/iblrig.gui.validation.SystemValidationDialog.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.validation.SystemValidationDialog +============================================ + +.. currentmodule:: iblrig.gui.validation + +.. inheritance-diagram:: SystemValidationDialog + :parts: 1 + +| + +.. autoclass:: SystemValidationDialog + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.validation.ValidatorItem.rst.txt b/_sources/api/iblrig.gui.validation.ValidatorItem.rst.txt new file mode 100644 index 000000000..061bdcd81 --- /dev/null +++ b/_sources/api/iblrig.gui.validation.ValidatorItem.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.validation.ValidatorItem +=================================== + +.. currentmodule:: iblrig.gui.validation + +.. inheritance-diagram:: ValidatorItem + :parts: 1 + +| + +.. autoclass:: ValidatorItem + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.validation.rst.txt b/_sources/api/iblrig.gui.validation.rst.txt new file mode 100644 index 000000000..e795638d5 --- /dev/null +++ b/_sources/api/iblrig.gui.validation.rst.txt @@ -0,0 +1,16 @@ +iblrig.gui.validation +===================== + +.. automodule:: iblrig.gui.validation + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + StatusItem + SystemValidationDialog + ValidatorItem + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.valve.CalibrationPlot.rst.txt b/_sources/api/iblrig.gui.valve.CalibrationPlot.rst.txt new file mode 100644 index 000000000..7bccd8c02 --- /dev/null +++ b/_sources/api/iblrig.gui.valve.CalibrationPlot.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.valve.CalibrationPlot +================================ + +.. currentmodule:: iblrig.gui.valve + +.. inheritance-diagram:: CalibrationPlot + :parts: 1 + +| + +.. autoclass:: CalibrationPlot + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.valve.ValveCalibrationDialog.rst.txt b/_sources/api/iblrig.gui.valve.ValveCalibrationDialog.rst.txt new file mode 100644 index 000000000..d4aa7a4ca --- /dev/null +++ b/_sources/api/iblrig.gui.valve.ValveCalibrationDialog.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.valve.ValveCalibrationDialog +======================================= + +.. currentmodule:: iblrig.gui.valve + +.. inheritance-diagram:: ValveCalibrationDialog + :parts: 1 + +| + +.. autoclass:: ValveCalibrationDialog + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.valve.rst.txt b/_sources/api/iblrig.gui.valve.rst.txt new file mode 100644 index 000000000..adbee8de1 --- /dev/null +++ b/_sources/api/iblrig.gui.valve.rst.txt @@ -0,0 +1,15 @@ +iblrig.gui.valve +================ + +.. automodule:: iblrig.gui.valve + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + CalibrationPlot + ValveCalibrationDialog + \ No newline at end of file diff --git a/_sources/api/iblrig.gui.wizard.LoginWindow.rst.txt b/_sources/api/iblrig.gui.wizard.LoginWindow.rst.txt new file mode 100644 index 000000000..032f997aa --- /dev/null +++ b/_sources/api/iblrig.gui.wizard.LoginWindow.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.wizard.LoginWindow +============================= + +.. currentmodule:: iblrig.gui.wizard + +.. inheritance-diagram:: LoginWindow + :parts: 1 + +| + +.. autoclass:: LoginWindow + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.wizard.RigWizard.rst.txt b/_sources/api/iblrig.gui.wizard.RigWizard.rst.txt new file mode 100644 index 000000000..6088beb3e --- /dev/null +++ b/_sources/api/iblrig.gui.wizard.RigWizard.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.wizard.RigWizard +=========================== + +.. currentmodule:: iblrig.gui.wizard + +.. inheritance-diagram:: RigWizard + :parts: 1 + +| + +.. autoclass:: RigWizard + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.wizard.RigWizardModel.rst.txt b/_sources/api/iblrig.gui.wizard.RigWizardModel.rst.txt new file mode 100644 index 000000000..db3308f53 --- /dev/null +++ b/_sources/api/iblrig.gui.wizard.RigWizardModel.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.wizard.RigWizardModel +================================ + +.. currentmodule:: iblrig.gui.wizard + +.. inheritance-diagram:: RigWizardModel + :parts: 1 + +| + +.. autoclass:: RigWizardModel + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.wizard.UpdateNotice.rst.txt b/_sources/api/iblrig.gui.wizard.UpdateNotice.rst.txt new file mode 100644 index 000000000..0960e4489 --- /dev/null +++ b/_sources/api/iblrig.gui.wizard.UpdateNotice.rst.txt @@ -0,0 +1,13 @@ +iblrig.gui.wizard.UpdateNotice +============================== + +.. currentmodule:: iblrig.gui.wizard + +.. inheritance-diagram:: UpdateNotice + :parts: 1 + +| + +.. autoclass:: UpdateNotice + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.gui.wizard.main.rst.txt b/_sources/api/iblrig.gui.wizard.main.rst.txt new file mode 100644 index 000000000..07d01d988 --- /dev/null +++ b/_sources/api/iblrig.gui.wizard.main.rst.txt @@ -0,0 +1,6 @@ +iblrig.gui.wizard.main +====================== + +.. currentmodule:: iblrig.gui.wizard + +.. autofunction:: main \ No newline at end of file diff --git a/_sources/api/iblrig.gui.wizard.rst.txt b/_sources/api/iblrig.gui.wizard.rst.txt new file mode 100644 index 000000000..b7bab6e18 --- /dev/null +++ b/_sources/api/iblrig.gui.wizard.rst.txt @@ -0,0 +1,25 @@ +iblrig.gui.wizard +================= + +.. automodule:: iblrig.gui.wizard + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + main + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + LoginWindow + RigWizard + RigWizardModel + UpdateNotice + \ No newline at end of file diff --git a/_sources/api/iblrig.hardware.Bpod.rst.txt b/_sources/api/iblrig.hardware.Bpod.rst.txt new file mode 100644 index 000000000..6922a6851 --- /dev/null +++ b/_sources/api/iblrig.hardware.Bpod.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware.Bpod +==================== + +.. currentmodule:: iblrig.hardware + +.. inheritance-diagram:: Bpod + :parts: 1 + +| + +.. autoclass:: Bpod + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware.MyRotaryEncoder.rst.txt b/_sources/api/iblrig.hardware.MyRotaryEncoder.rst.txt new file mode 100644 index 000000000..30bd735cc --- /dev/null +++ b/_sources/api/iblrig.hardware.MyRotaryEncoder.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware.MyRotaryEncoder +=============================== + +.. currentmodule:: iblrig.hardware + +.. inheritance-diagram:: MyRotaryEncoder + :parts: 1 + +| + +.. autoclass:: MyRotaryEncoder + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware.SOFTCODE.rst.txt b/_sources/api/iblrig.hardware.SOFTCODE.rst.txt new file mode 100644 index 000000000..02281047e --- /dev/null +++ b/_sources/api/iblrig.hardware.SOFTCODE.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware.SOFTCODE +======================== + +.. currentmodule:: iblrig.hardware + +.. inheritance-diagram:: SOFTCODE + :parts: 1 + +| + +.. autoclass:: SOFTCODE + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware.restart_com_port.rst.txt b/_sources/api/iblrig.hardware.restart_com_port.rst.txt new file mode 100644 index 000000000..cd1683bb9 --- /dev/null +++ b/_sources/api/iblrig.hardware.restart_com_port.rst.txt @@ -0,0 +1,6 @@ +iblrig.hardware.restart\_com\_port +================================== + +.. currentmodule:: iblrig.hardware + +.. autofunction:: restart_com_port \ No newline at end of file diff --git a/_sources/api/iblrig.hardware.rst.txt b/_sources/api/iblrig.hardware.rst.txt new file mode 100644 index 000000000..0251b6029 --- /dev/null +++ b/_sources/api/iblrig.hardware.rst.txt @@ -0,0 +1,25 @@ +iblrig.hardware +=============== + +.. automodule:: iblrig.hardware + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + restart_com_port + sound_device_factory + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Bpod + MyRotaryEncoder + SOFTCODE + \ No newline at end of file diff --git a/_sources/api/iblrig.hardware.sound_device_factory.rst.txt b/_sources/api/iblrig.hardware.sound_device_factory.rst.txt new file mode 100644 index 000000000..fd5b75834 --- /dev/null +++ b/_sources/api/iblrig.hardware.sound_device_factory.rst.txt @@ -0,0 +1,6 @@ +iblrig.hardware.sound\_device\_factory +====================================== + +.. currentmodule:: iblrig.hardware + +.. autofunction:: sound_device_factory \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.Result.rst.txt b/_sources/api/iblrig.hardware_validation.Result.rst.txt new file mode 100644 index 000000000..5c418108d --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.Result.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.Result +================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: Result + :parts: 1 + +| + +.. autoclass:: Result + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.Status.rst.txt b/_sources/api/iblrig.hardware_validation.Status.rst.txt new file mode 100644 index 000000000..9fc45d48f --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.Status.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.Status +================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: Status + :parts: 1 + +| + +.. autoclass:: Status + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidateHardwareError.rst.txt b/_sources/api/iblrig.hardware_validation.ValidateHardwareError.rst.txt new file mode 100644 index 000000000..653bd5fbb --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidateHardwareError.rst.txt @@ -0,0 +1,6 @@ +iblrig.hardware\_validation.ValidateHardwareError +================================================= + +.. currentmodule:: iblrig.hardware_validation + +.. autoexception:: ValidateHardwareError \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.Validator.rst.txt b/_sources/api/iblrig.hardware_validation.Validator.rst.txt new file mode 100644 index 000000000..77d875a4f --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.Validator.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.Validator +===================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: Validator + :parts: 1 + +| + +.. autoclass:: Validator + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorAlyx.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorAlyx.rst.txt new file mode 100644 index 000000000..63e17ffa5 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorAlyx.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorAlyx +========================================= + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorAlyx + :parts: 1 + +| + +.. autoclass:: ValidatorAlyx + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorAmbientModule.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorAmbientModule.rst.txt new file mode 100644 index 000000000..fc5a955c1 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorAmbientModule.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorAmbientModule +================================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorAmbientModule + :parts: 1 + +| + +.. autoclass:: ValidatorAmbientModule + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorBpod.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorBpod.rst.txt new file mode 100644 index 000000000..513510d0e --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorBpod.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorBpod +========================================= + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorBpod + :parts: 1 + +| + +.. autoclass:: ValidatorBpod + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorCamera.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorCamera.rst.txt new file mode 100644 index 000000000..ba13413cf --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorCamera.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorCamera +=========================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorCamera + :parts: 1 + +| + +.. autoclass:: ValidatorCamera + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorFrame2TTL.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorFrame2TTL.rst.txt new file mode 100644 index 000000000..77a79ebb8 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorFrame2TTL.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorFrame2TTL +============================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorFrame2TTL + :parts: 1 + +| + +.. autoclass:: ValidatorFrame2TTL + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorGit.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorGit.rst.txt new file mode 100644 index 000000000..dfc813b3c --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorGit.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorGit +======================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorGit + :parts: 1 + +| + +.. autoclass:: ValidatorGit + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorMic.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorMic.rst.txt new file mode 100644 index 000000000..4c3f6d951 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorMic.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorMic +======================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorMic + :parts: 1 + +| + +.. autoclass:: ValidatorMic + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.rst.txt new file mode 100644 index 000000000..9d6dca3e8 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorRotaryEncoderModule +======================================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorRotaryEncoderModule + :parts: 1 + +| + +.. autoclass:: ValidatorRotaryEncoderModule + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorSerial.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorSerial.rst.txt new file mode 100644 index 000000000..dd5bb421e --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorSerial.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorSerial +=========================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorSerial + :parts: 1 + +| + +.. autoclass:: ValidatorSerial + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorSound.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorSound.rst.txt new file mode 100644 index 000000000..2e2641486 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorSound.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorSound +========================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorSound + :parts: 1 + +| + +.. autoclass:: ValidatorSound + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.ValidatorValve.rst.txt b/_sources/api/iblrig.hardware_validation.ValidatorValve.rst.txt new file mode 100644 index 000000000..1dac06cbc --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.ValidatorValve.rst.txt @@ -0,0 +1,13 @@ +iblrig.hardware\_validation.ValidatorValve +========================================== + +.. currentmodule:: iblrig.hardware_validation + +.. inheritance-diagram:: ValidatorValve + :parts: 1 + +| + +.. autoclass:: ValidatorValve + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.get_all_validators.rst.txt b/_sources/api/iblrig.hardware_validation.get_all_validators.rst.txt new file mode 100644 index 000000000..1544db17e --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.get_all_validators.rst.txt @@ -0,0 +1,6 @@ +iblrig.hardware\_validation.get\_all\_validators +================================================ + +.. currentmodule:: iblrig.hardware_validation + +.. autofunction:: get_all_validators \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.rst.txt b/_sources/api/iblrig.hardware_validation.rst.txt new file mode 100644 index 000000000..11f2de743 --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.rst.txt @@ -0,0 +1,45 @@ +iblrig.hardware\_validation +=========================== + +.. automodule:: iblrig.hardware_validation + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + get_all_validators + run_all_validators + run_all_validators_cli + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Result + Status + Validator + ValidatorAlyx + ValidatorAmbientModule + ValidatorBpod + ValidatorCamera + ValidatorFrame2TTL + ValidatorGit + ValidatorMic + ValidatorRotaryEncoderModule + ValidatorSerial + ValidatorSound + ValidatorValve + + .. rubric:: Exceptions + + .. autosummary:: + :nosignatures: + :toctree: + + ValidateHardwareError + \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.run_all_validators.rst.txt b/_sources/api/iblrig.hardware_validation.run_all_validators.rst.txt new file mode 100644 index 000000000..a2adb366a --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.run_all_validators.rst.txt @@ -0,0 +1,6 @@ +iblrig.hardware\_validation.run\_all\_validators +================================================ + +.. currentmodule:: iblrig.hardware_validation + +.. autofunction:: run_all_validators \ No newline at end of file diff --git a/_sources/api/iblrig.hardware_validation.run_all_validators_cli.rst.txt b/_sources/api/iblrig.hardware_validation.run_all_validators_cli.rst.txt new file mode 100644 index 000000000..1be99f25a --- /dev/null +++ b/_sources/api/iblrig.hardware_validation.run_all_validators_cli.rst.txt @@ -0,0 +1,6 @@ +iblrig.hardware\_validation.run\_all\_validators\_cli +===================================================== + +.. currentmodule:: iblrig.hardware_validation + +.. autofunction:: run_all_validators_cli \ No newline at end of file diff --git a/_sources/api/iblrig.hifi.HiFi.rst.txt b/_sources/api/iblrig.hifi.HiFi.rst.txt new file mode 100644 index 000000000..670cecc35 --- /dev/null +++ b/_sources/api/iblrig.hifi.HiFi.rst.txt @@ -0,0 +1,13 @@ +iblrig.hifi.HiFi +================ + +.. currentmodule:: iblrig.hifi + +.. inheritance-diagram:: HiFi + :parts: 1 + +| + +.. autoclass:: HiFi + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.hifi.HiFiException.rst.txt b/_sources/api/iblrig.hifi.HiFiException.rst.txt new file mode 100644 index 000000000..ed8296551 --- /dev/null +++ b/_sources/api/iblrig.hifi.HiFiException.rst.txt @@ -0,0 +1,6 @@ +iblrig.hifi.HiFiException +========================= + +.. currentmodule:: iblrig.hifi + +.. autoexception:: HiFiException \ No newline at end of file diff --git a/_sources/api/iblrig.hifi.rst.txt b/_sources/api/iblrig.hifi.rst.txt new file mode 100644 index 000000000..90b3e644b --- /dev/null +++ b/_sources/api/iblrig.hifi.rst.txt @@ -0,0 +1,22 @@ +iblrig.hifi +=========== + +.. automodule:: iblrig.hifi + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + HiFi + + .. rubric:: Exceptions + + .. autosummary:: + :nosignatures: + :toctree: + + HiFiException + \ No newline at end of file diff --git a/_sources/api/iblrig.misc.draw_contrast.rst.txt b/_sources/api/iblrig.misc.draw_contrast.rst.txt new file mode 100644 index 000000000..e2a231e2f --- /dev/null +++ b/_sources/api/iblrig.misc.draw_contrast.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.draw\_contrast +========================== + +.. currentmodule:: iblrig.misc + +.. autofunction:: draw_contrast \ No newline at end of file diff --git a/_sources/api/iblrig.misc.get_biased_probs.rst.txt b/_sources/api/iblrig.misc.get_biased_probs.rst.txt new file mode 100644 index 000000000..ab64e1a32 --- /dev/null +++ b/_sources/api/iblrig.misc.get_biased_probs.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.get\_biased\_probs +============================== + +.. currentmodule:: iblrig.misc + +.. autofunction:: get_biased_probs \ No newline at end of file diff --git a/_sources/api/iblrig.misc.get_port_events.rst.txt b/_sources/api/iblrig.misc.get_port_events.rst.txt new file mode 100644 index 000000000..43bed9fc2 --- /dev/null +++ b/_sources/api/iblrig.misc.get_port_events.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.get\_port\_events +============================= + +.. currentmodule:: iblrig.misc + +.. autofunction:: get_port_events \ No newline at end of file diff --git a/_sources/api/iblrig.misc.get_session_path.rst.txt b/_sources/api/iblrig.misc.get_session_path.rst.txt new file mode 100644 index 000000000..46e52cc7c --- /dev/null +++ b/_sources/api/iblrig.misc.get_session_path.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.get\_session\_path +============================== + +.. currentmodule:: iblrig.misc + +.. autofunction:: get_session_path \ No newline at end of file diff --git a/_sources/api/iblrig.misc.get_task_argument_parser.rst.txt b/_sources/api/iblrig.misc.get_task_argument_parser.rst.txt new file mode 100644 index 000000000..9c4cb3831 --- /dev/null +++ b/_sources/api/iblrig.misc.get_task_argument_parser.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.get\_task\_argument\_parser +======================================= + +.. currentmodule:: iblrig.misc + +.. autofunction:: get_task_argument_parser \ No newline at end of file diff --git a/_sources/api/iblrig.misc.get_task_arguments.rst.txt b/_sources/api/iblrig.misc.get_task_arguments.rst.txt new file mode 100644 index 000000000..b6059e1c7 --- /dev/null +++ b/_sources/api/iblrig.misc.get_task_arguments.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.get\_task\_arguments +================================ + +.. currentmodule:: iblrig.misc + +.. autofunction:: get_task_arguments \ No newline at end of file diff --git a/_sources/api/iblrig.misc.online_std.rst.txt b/_sources/api/iblrig.misc.online_std.rst.txt new file mode 100644 index 000000000..ac62647ab --- /dev/null +++ b/_sources/api/iblrig.misc.online_std.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.online\_std +======================= + +.. currentmodule:: iblrig.misc + +.. autofunction:: online_std \ No newline at end of file diff --git a/_sources/api/iblrig.misc.rst.txt b/_sources/api/iblrig.misc.rst.txt new file mode 100644 index 000000000..ac99b7893 --- /dev/null +++ b/_sources/api/iblrig.misc.rst.txt @@ -0,0 +1,20 @@ +iblrig.misc +=========== + +.. automodule:: iblrig.misc + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + draw_contrast + get_biased_probs + get_port_events + get_session_path + get_task_argument_parser + get_task_arguments + online_std + truncated_exponential + \ No newline at end of file diff --git a/_sources/api/iblrig.misc.truncated_exponential.rst.txt b/_sources/api/iblrig.misc.truncated_exponential.rst.txt new file mode 100644 index 000000000..550875371 --- /dev/null +++ b/_sources/api/iblrig.misc.truncated_exponential.rst.txt @@ -0,0 +1,6 @@ +iblrig.misc.truncated\_exponential +================================== + +.. currentmodule:: iblrig.misc + +.. autofunction:: truncated_exponential \ No newline at end of file diff --git a/_sources/api/iblrig.net.Auxiliaries.rst.txt b/_sources/api/iblrig.net.Auxiliaries.rst.txt new file mode 100644 index 000000000..08688e245 --- /dev/null +++ b/_sources/api/iblrig.net.Auxiliaries.rst.txt @@ -0,0 +1,13 @@ +iblrig.net.Auxiliaries +====================== + +.. currentmodule:: iblrig.net + +.. inheritance-diagram:: Auxiliaries + :parts: 1 + +| + +.. autoclass:: Auxiliaries + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.net.ExpInfo.rst.txt b/_sources/api/iblrig.net.ExpInfo.rst.txt new file mode 100644 index 000000000..b3009d9dd --- /dev/null +++ b/_sources/api/iblrig.net.ExpInfo.rst.txt @@ -0,0 +1,13 @@ +iblrig.net.ExpInfo +================== + +.. currentmodule:: iblrig.net + +.. inheritance-diagram:: ExpInfo + :parts: 1 + +| + +.. autoclass:: ExpInfo + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.net.check_uri_match.rst.txt b/_sources/api/iblrig.net.check_uri_match.rst.txt new file mode 100644 index 000000000..d4a41068c --- /dev/null +++ b/_sources/api/iblrig.net.check_uri_match.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.check\_uri\_match +============================ + +.. currentmodule:: iblrig.net + +.. autofunction:: check_uri_match \ No newline at end of file diff --git a/_sources/api/iblrig.net.get_remote_devices.rst.txt b/_sources/api/iblrig.net.get_remote_devices.rst.txt new file mode 100644 index 000000000..8ff02de6d --- /dev/null +++ b/_sources/api/iblrig.net.get_remote_devices.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.get\_remote\_devices +=============================== + +.. currentmodule:: iblrig.net + +.. autofunction:: get_remote_devices \ No newline at end of file diff --git a/_sources/api/iblrig.net.get_remote_devices_file.rst.txt b/_sources/api/iblrig.net.get_remote_devices_file.rst.txt new file mode 100644 index 000000000..16d455fcb --- /dev/null +++ b/_sources/api/iblrig.net.get_remote_devices_file.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.get\_remote\_devices\_file +===================================== + +.. currentmodule:: iblrig.net + +.. autofunction:: get_remote_devices_file \ No newline at end of file diff --git a/_sources/api/iblrig.net.get_server_communicator.rst.txt b/_sources/api/iblrig.net.get_server_communicator.rst.txt new file mode 100644 index 000000000..d450165cf --- /dev/null +++ b/_sources/api/iblrig.net.get_server_communicator.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.get\_server\_communicator +==================================== + +.. currentmodule:: iblrig.net + +.. autofunction:: get_server_communicator \ No newline at end of file diff --git a/_sources/api/iblrig.net.install_alyx_token.rst.txt b/_sources/api/iblrig.net.install_alyx_token.rst.txt new file mode 100644 index 000000000..e728a81f1 --- /dev/null +++ b/_sources/api/iblrig.net.install_alyx_token.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.install\_alyx\_token +=============================== + +.. currentmodule:: iblrig.net + +.. autofunction:: install_alyx_token \ No newline at end of file diff --git a/_sources/api/iblrig.net.read_stdin.rst.txt b/_sources/api/iblrig.net.read_stdin.rst.txt new file mode 100644 index 000000000..35a3c2014 --- /dev/null +++ b/_sources/api/iblrig.net.read_stdin.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.read\_stdin +====================== + +.. currentmodule:: iblrig.net + +.. autofunction:: read_stdin \ No newline at end of file diff --git a/_sources/api/iblrig.net.rst.txt b/_sources/api/iblrig.net.rst.txt new file mode 100644 index 000000000..7c3a1c266 --- /dev/null +++ b/_sources/api/iblrig.net.rst.txt @@ -0,0 +1,29 @@ +iblrig.net +========== + +.. automodule:: iblrig.net + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + check_uri_match + get_remote_devices + get_remote_devices_file + get_server_communicator + install_alyx_token + read_stdin + update_alyx_token + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Auxiliaries + ExpInfo + \ No newline at end of file diff --git a/_sources/api/iblrig.net.update_alyx_token.rst.txt b/_sources/api/iblrig.net.update_alyx_token.rst.txt new file mode 100644 index 000000000..7eabc3ac4 --- /dev/null +++ b/_sources/api/iblrig.net.update_alyx_token.rst.txt @@ -0,0 +1,6 @@ +iblrig.net.update\_alyx\_token +============================== + +.. currentmodule:: iblrig.net + +.. autofunction:: update_alyx_token \ No newline at end of file diff --git a/_sources/api/iblrig.online_plots.DataModel.rst.txt b/_sources/api/iblrig.online_plots.DataModel.rst.txt new file mode 100644 index 000000000..6e29c942d --- /dev/null +++ b/_sources/api/iblrig.online_plots.DataModel.rst.txt @@ -0,0 +1,13 @@ +iblrig.online\_plots.DataModel +============================== + +.. currentmodule:: iblrig.online_plots + +.. inheritance-diagram:: DataModel + :parts: 1 + +| + +.. autoclass:: DataModel + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.online_plots.OnlinePlots.rst.txt b/_sources/api/iblrig.online_plots.OnlinePlots.rst.txt new file mode 100644 index 000000000..456cefd4b --- /dev/null +++ b/_sources/api/iblrig.online_plots.OnlinePlots.rst.txt @@ -0,0 +1,13 @@ +iblrig.online\_plots.OnlinePlots +================================ + +.. currentmodule:: iblrig.online_plots + +.. inheritance-diagram:: OnlinePlots + :parts: 1 + +| + +.. autoclass:: OnlinePlots + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.online_plots.rst.txt b/_sources/api/iblrig.online_plots.rst.txt new file mode 100644 index 000000000..afc8ccb6a --- /dev/null +++ b/_sources/api/iblrig.online_plots.rst.txt @@ -0,0 +1,15 @@ +iblrig.online\_plots +==================== + +.. automodule:: iblrig.online_plots + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + DataModel + OnlinePlots + \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.create_bonsai_layout_from_template.rst.txt b/_sources/api/iblrig.path_helper.create_bonsai_layout_from_template.rst.txt new file mode 100644 index 000000000..006943c66 --- /dev/null +++ b/_sources/api/iblrig.path_helper.create_bonsai_layout_from_template.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.create\_bonsai\_layout\_from\_template +========================================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: create_bonsai_layout_from_template \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.get_commit_hash.rst.txt b/_sources/api/iblrig.path_helper.get_commit_hash.rst.txt new file mode 100644 index 000000000..337e4b797 --- /dev/null +++ b/_sources/api/iblrig.path_helper.get_commit_hash.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.get\_commit\_hash +===================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: get_commit_hash \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.get_local_and_remote_paths.rst.txt b/_sources/api/iblrig.path_helper.get_local_and_remote_paths.rst.txt new file mode 100644 index 000000000..a0ad637cd --- /dev/null +++ b/_sources/api/iblrig.path_helper.get_local_and_remote_paths.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.get\_local\_and\_remote\_paths +================================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: get_local_and_remote_paths \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.iterate_collection.rst.txt b/_sources/api/iblrig.path_helper.iterate_collection.rst.txt new file mode 100644 index 000000000..096292c52 --- /dev/null +++ b/_sources/api/iblrig.path_helper.iterate_collection.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.iterate\_collection +======================================= + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: iterate_collection \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.iterate_previous_sessions.rst.txt b/_sources/api/iblrig.path_helper.iterate_previous_sessions.rst.txt new file mode 100644 index 000000000..602e2bc6d --- /dev/null +++ b/_sources/api/iblrig.path_helper.iterate_previous_sessions.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.iterate\_previous\_sessions +=============================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: iterate_previous_sessions \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.load_pydantic_yaml.rst.txt b/_sources/api/iblrig.path_helper.load_pydantic_yaml.rst.txt new file mode 100644 index 000000000..e8d8ea380 --- /dev/null +++ b/_sources/api/iblrig.path_helper.load_pydantic_yaml.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.load\_pydantic\_yaml +======================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: load_pydantic_yaml \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.patch_settings.rst.txt b/_sources/api/iblrig.path_helper.patch_settings.rst.txt new file mode 100644 index 000000000..7d62d8eb0 --- /dev/null +++ b/_sources/api/iblrig.path_helper.patch_settings.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.patch\_settings +=================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: patch_settings \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.rst.txt b/_sources/api/iblrig.path_helper.rst.txt new file mode 100644 index 000000000..19d9f64d7 --- /dev/null +++ b/_sources/api/iblrig.path_helper.rst.txt @@ -0,0 +1,20 @@ +iblrig.path\_helper +=================== + +.. automodule:: iblrig.path_helper + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + create_bonsai_layout_from_template + get_commit_hash + get_local_and_remote_paths + iterate_collection + iterate_previous_sessions + load_pydantic_yaml + patch_settings + save_pydantic_yaml + \ No newline at end of file diff --git a/_sources/api/iblrig.path_helper.save_pydantic_yaml.rst.txt b/_sources/api/iblrig.path_helper.save_pydantic_yaml.rst.txt new file mode 100644 index 000000000..1ebf6d4ed --- /dev/null +++ b/_sources/api/iblrig.path_helper.save_pydantic_yaml.rst.txt @@ -0,0 +1,6 @@ +iblrig.path\_helper.save\_pydantic\_yaml +======================================== + +.. currentmodule:: iblrig.path_helper + +.. autofunction:: save_pydantic_yaml \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.BunchModel.rst.txt b/_sources/api/iblrig.pydantic_definitions.BunchModel.rst.txt new file mode 100644 index 000000000..dfe37e61f --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.BunchModel.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.BunchModel +======================================= + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: BunchModel + :parts: 1 + +| + +.. autoclass:: BunchModel + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.ExistingFilePath.rst.txt b/_sources/api/iblrig.pydantic_definitions.ExistingFilePath.rst.txt new file mode 100644 index 000000000..5e41cfc4c --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.ExistingFilePath.rst.txt @@ -0,0 +1,6 @@ +iblrig.pydantic\_definitions.ExistingFilePath +============================================= + +.. currentmodule:: iblrig.pydantic_definitions + +.. autodata:: ExistingFilePath \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettings.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettings.rst.txt new file mode 100644 index 000000000..128ccc7e4 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettings.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettings +============================================= + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettings + :parts: 1 + +| + +.. autoclass:: HardwareSettings + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsBpod.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsBpod.rst.txt new file mode 100644 index 000000000..0a7000872 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsBpod.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsBpod +================================================= + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsBpod + :parts: 1 + +| + +.. autoclass:: HardwareSettingsBpod + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsCamera.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsCamera.rst.txt new file mode 100644 index 000000000..e25d5dc69 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsCamera.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsCamera +=================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsCamera + :parts: 1 + +| + +.. autoclass:: HardwareSettingsCamera + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.rst.txt new file mode 100644 index 000000000..88156288f --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsCameraWorkflow +=========================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsCameraWorkflow + :parts: 1 + +| + +.. autoclass:: HardwareSettingsCameraWorkflow + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.rst.txt new file mode 100644 index 000000000..b14e82067 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsFrame2TTL +====================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsFrame2TTL + :parts: 1 + +| + +.. autoclass:: HardwareSettingsFrame2TTL + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.rst.txt new file mode 100644 index 000000000..20925e45d --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsMicrophone +======================================================= + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsMicrophone + :parts: 1 + +| + +.. autoclass:: HardwareSettingsMicrophone + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.rst.txt new file mode 100644 index 000000000..9d057088d --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsRotaryEncoder +========================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsRotaryEncoder + :parts: 1 + +| + +.. autoclass:: HardwareSettingsRotaryEncoder + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsScale.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsScale.rst.txt new file mode 100644 index 000000000..6f1345cfd --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsScale.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsScale +================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsScale + :parts: 1 + +| + +.. autoclass:: HardwareSettingsScale + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsScreen.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsScreen.rst.txt new file mode 100644 index 000000000..ccfb132f2 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsScreen.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsScreen +=================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsScreen + :parts: 1 + +| + +.. autoclass:: HardwareSettingsScreen + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsSound.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsSound.rst.txt new file mode 100644 index 000000000..152128df4 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsSound.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsSound +================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsSound + :parts: 1 + +| + +.. autoclass:: HardwareSettingsSound + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.HardwareSettingsValve.rst.txt b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsValve.rst.txt new file mode 100644 index 000000000..7c3ce4757 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.HardwareSettingsValve.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.HardwareSettingsValve +================================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: HardwareSettingsValve + :parts: 1 + +| + +.. autoclass:: HardwareSettingsValve + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.RigSettings.rst.txt b/_sources/api/iblrig.pydantic_definitions.RigSettings.rst.txt new file mode 100644 index 000000000..e04229370 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.RigSettings.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.RigSettings +======================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: RigSettings + :parts: 1 + +| + +.. autoclass:: RigSettings + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.TrialDataModel.rst.txt b/_sources/api/iblrig.pydantic_definitions.TrialDataModel.rst.txt new file mode 100644 index 000000000..ce884a557 --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.TrialDataModel.rst.txt @@ -0,0 +1,13 @@ +iblrig.pydantic\_definitions.TrialDataModel +=========================================== + +.. currentmodule:: iblrig.pydantic_definitions + +.. inheritance-diagram:: TrialDataModel + :parts: 1 + +| + +.. autoclass:: TrialDataModel + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.pydantic_definitions.rst.txt b/_sources/api/iblrig.pydantic_definitions.rst.txt new file mode 100644 index 000000000..7bca9976b --- /dev/null +++ b/_sources/api/iblrig.pydantic_definitions.rst.txt @@ -0,0 +1,35 @@ +iblrig.pydantic\_definitions +============================ + +.. automodule:: iblrig.pydantic_definitions + + .. rubric:: Module Attributes + + .. autosummary:: + :nosignatures: + :toctree: + + ExistingFilePath + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + BunchModel + HardwareSettings + HardwareSettingsBpod + HardwareSettingsCamera + HardwareSettingsCameraWorkflow + HardwareSettingsFrame2TTL + HardwareSettingsMicrophone + HardwareSettingsRotaryEncoder + HardwareSettingsScale + HardwareSettingsScreen + HardwareSettingsSound + HardwareSettingsValve + RigSettings + TrialDataModel + \ No newline at end of file diff --git a/_sources/api/iblrig.raw_data_loaders.load_task_jsonable.rst.txt b/_sources/api/iblrig.raw_data_loaders.load_task_jsonable.rst.txt new file mode 100644 index 000000000..de07e7e3d --- /dev/null +++ b/_sources/api/iblrig.raw_data_loaders.load_task_jsonable.rst.txt @@ -0,0 +1,6 @@ +iblrig.raw\_data\_loaders.load\_task\_jsonable +============================================== + +.. currentmodule:: iblrig.raw_data_loaders + +.. autofunction:: load_task_jsonable \ No newline at end of file diff --git a/_sources/api/iblrig.raw_data_loaders.rst.txt b/_sources/api/iblrig.raw_data_loaders.rst.txt new file mode 100644 index 000000000..0d7b81b39 --- /dev/null +++ b/_sources/api/iblrig.raw_data_loaders.rst.txt @@ -0,0 +1,13 @@ +iblrig.raw\_data\_loaders +========================= + +.. automodule:: iblrig.raw_data_loaders + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + load_task_jsonable + \ No newline at end of file diff --git a/_sources/api/iblrig.rig_component.RigComponent.rst.txt b/_sources/api/iblrig.rig_component.RigComponent.rst.txt new file mode 100644 index 000000000..5effd559d --- /dev/null +++ b/_sources/api/iblrig.rig_component.RigComponent.rst.txt @@ -0,0 +1,13 @@ +iblrig.rig\_component.RigComponent +================================== + +.. currentmodule:: iblrig.rig_component + +.. inheritance-diagram:: RigComponent + :parts: 1 + +| + +.. autoclass:: RigComponent + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.rig_component.rst.txt b/_sources/api/iblrig.rig_component.rst.txt new file mode 100644 index 000000000..0b20efee6 --- /dev/null +++ b/_sources/api/iblrig.rig_component.rst.txt @@ -0,0 +1,14 @@ +iblrig.rig\_component +===================== + +.. automodule:: iblrig.rig_component + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + RigComponent + \ No newline at end of file diff --git a/_sources/api/iblrig.rst.txt b/_sources/api/iblrig.rst.txt new file mode 100644 index 000000000..84d41c262 --- /dev/null +++ b/_sources/api/iblrig.rst.txt @@ -0,0 +1,73 @@ +iblrig +====== + +.. automodule:: iblrig + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + base_choice_world + + base_tasks + + choiceworld + + commands + + constants + + ephys + + frame2ttl + + graphic + + gui + + hardware + + hardware_validation + + hifi + + misc + + net + + online_plots + + path_helper + + pydantic_definitions + + raw_data_loaders + + rig_component + + scale + + serial_singleton + + session_creator + + sound + + tools + + transfer_experiments + + upgrade_iblrig + + valve + + version_management + + video + + video_pyspin + diff --git a/_sources/api/iblrig.scale.Scale.rst.txt b/_sources/api/iblrig.scale.Scale.rst.txt new file mode 100644 index 000000000..aac5fbb6d --- /dev/null +++ b/_sources/api/iblrig.scale.Scale.rst.txt @@ -0,0 +1,13 @@ +iblrig.scale.Scale +================== + +.. currentmodule:: iblrig.scale + +.. inheritance-diagram:: Scale + :parts: 1 + +| + +.. autoclass:: Scale + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.scale.ScaleData.rst.txt b/_sources/api/iblrig.scale.ScaleData.rst.txt new file mode 100644 index 000000000..bc9c04bbc --- /dev/null +++ b/_sources/api/iblrig.scale.ScaleData.rst.txt @@ -0,0 +1,13 @@ +iblrig.scale.ScaleData +====================== + +.. currentmodule:: iblrig.scale + +.. inheritance-diagram:: ScaleData + :parts: 1 + +| + +.. autoclass:: ScaleData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.scale.rst.txt b/_sources/api/iblrig.scale.rst.txt new file mode 100644 index 000000000..636d927fd --- /dev/null +++ b/_sources/api/iblrig.scale.rst.txt @@ -0,0 +1,15 @@ +iblrig.scale +============ + +.. automodule:: iblrig.scale + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Scale + ScaleData + \ No newline at end of file diff --git a/_sources/api/iblrig.serial_singleton.SerialSingleton.rst.txt b/_sources/api/iblrig.serial_singleton.SerialSingleton.rst.txt new file mode 100644 index 000000000..446b59f93 --- /dev/null +++ b/_sources/api/iblrig.serial_singleton.SerialSingleton.rst.txt @@ -0,0 +1,13 @@ +iblrig.serial\_singleton.SerialSingleton +======================================== + +.. currentmodule:: iblrig.serial_singleton + +.. inheritance-diagram:: SerialSingleton + :parts: 1 + +| + +.. autoclass:: SerialSingleton + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.serial_singleton.SerialSingletonException.rst.txt b/_sources/api/iblrig.serial_singleton.SerialSingletonException.rst.txt new file mode 100644 index 000000000..434e53c6f --- /dev/null +++ b/_sources/api/iblrig.serial_singleton.SerialSingletonException.rst.txt @@ -0,0 +1,6 @@ +iblrig.serial\_singleton.SerialSingletonException +================================================= + +.. currentmodule:: iblrig.serial_singleton + +.. autoexception:: SerialSingletonException \ No newline at end of file diff --git a/_sources/api/iblrig.serial_singleton.filter_ports.rst.txt b/_sources/api/iblrig.serial_singleton.filter_ports.rst.txt new file mode 100644 index 000000000..15c8144e7 --- /dev/null +++ b/_sources/api/iblrig.serial_singleton.filter_ports.rst.txt @@ -0,0 +1,6 @@ +iblrig.serial\_singleton.filter\_ports +====================================== + +.. currentmodule:: iblrig.serial_singleton + +.. autofunction:: filter_ports \ No newline at end of file diff --git a/_sources/api/iblrig.serial_singleton.get_port_from_serial_number.rst.txt b/_sources/api/iblrig.serial_singleton.get_port_from_serial_number.rst.txt new file mode 100644 index 000000000..da77d085f --- /dev/null +++ b/_sources/api/iblrig.serial_singleton.get_port_from_serial_number.rst.txt @@ -0,0 +1,6 @@ +iblrig.serial\_singleton.get\_port\_from\_serial\_number +======================================================== + +.. currentmodule:: iblrig.serial_singleton + +.. autofunction:: get_port_from_serial_number \ No newline at end of file diff --git a/_sources/api/iblrig.serial_singleton.get_serial_number_from_port.rst.txt b/_sources/api/iblrig.serial_singleton.get_serial_number_from_port.rst.txt new file mode 100644 index 000000000..cd11c86e3 --- /dev/null +++ b/_sources/api/iblrig.serial_singleton.get_serial_number_from_port.rst.txt @@ -0,0 +1,6 @@ +iblrig.serial\_singleton.get\_serial\_number\_from\_port +======================================================== + +.. currentmodule:: iblrig.serial_singleton + +.. autofunction:: get_serial_number_from_port \ No newline at end of file diff --git a/_sources/api/iblrig.serial_singleton.rst.txt b/_sources/api/iblrig.serial_singleton.rst.txt new file mode 100644 index 000000000..7ced38277 --- /dev/null +++ b/_sources/api/iblrig.serial_singleton.rst.txt @@ -0,0 +1,32 @@ +iblrig.serial\_singleton +======================== + +.. automodule:: iblrig.serial_singleton + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + filter_ports + get_port_from_serial_number + get_serial_number_from_port + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + SerialSingleton + + .. rubric:: Exceptions + + .. autosummary:: + :nosignatures: + :toctree: + + SerialSingletonException + \ No newline at end of file diff --git a/_sources/api/iblrig.session_creator.draw_block_len.rst.txt b/_sources/api/iblrig.session_creator.draw_block_len.rst.txt new file mode 100644 index 000000000..b280ed901 --- /dev/null +++ b/_sources/api/iblrig.session_creator.draw_block_len.rst.txt @@ -0,0 +1,6 @@ +iblrig.session\_creator.draw\_block\_len +======================================== + +.. currentmodule:: iblrig.session_creator + +.. autofunction:: draw_block_len \ No newline at end of file diff --git a/_sources/api/iblrig.session_creator.draw_position.rst.txt b/_sources/api/iblrig.session_creator.draw_position.rst.txt new file mode 100644 index 000000000..462441fbf --- /dev/null +++ b/_sources/api/iblrig.session_creator.draw_position.rst.txt @@ -0,0 +1,6 @@ +iblrig.session\_creator.draw\_position +====================================== + +.. currentmodule:: iblrig.session_creator + +.. autofunction:: draw_position \ No newline at end of file diff --git a/_sources/api/iblrig.session_creator.make_ephyscw_pc.rst.txt b/_sources/api/iblrig.session_creator.make_ephyscw_pc.rst.txt new file mode 100644 index 000000000..e0f4670e8 --- /dev/null +++ b/_sources/api/iblrig.session_creator.make_ephyscw_pc.rst.txt @@ -0,0 +1,6 @@ +iblrig.session\_creator.make\_ephyscw\_pc +========================================= + +.. currentmodule:: iblrig.session_creator + +.. autofunction:: make_ephyscw_pc \ No newline at end of file diff --git a/_sources/api/iblrig.session_creator.rst.txt b/_sources/api/iblrig.session_creator.rst.txt new file mode 100644 index 000000000..e2db0a1d0 --- /dev/null +++ b/_sources/api/iblrig.session_creator.rst.txt @@ -0,0 +1,15 @@ +iblrig.session\_creator +======================= + +.. automodule:: iblrig.session_creator + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + draw_block_len + draw_position + make_ephyscw_pc + \ No newline at end of file diff --git a/_sources/api/iblrig.sound.configure_sound_card.rst.txt b/_sources/api/iblrig.sound.configure_sound_card.rst.txt new file mode 100644 index 000000000..305949f61 --- /dev/null +++ b/_sources/api/iblrig.sound.configure_sound_card.rst.txt @@ -0,0 +1,6 @@ +iblrig.sound.configure\_sound\_card +=================================== + +.. currentmodule:: iblrig.sound + +.. autofunction:: configure_sound_card \ No newline at end of file diff --git a/_sources/api/iblrig.sound.format_sound.rst.txt b/_sources/api/iblrig.sound.format_sound.rst.txt new file mode 100644 index 000000000..4bf1f0ec3 --- /dev/null +++ b/_sources/api/iblrig.sound.format_sound.rst.txt @@ -0,0 +1,6 @@ +iblrig.sound.format\_sound +========================== + +.. currentmodule:: iblrig.sound + +.. autofunction:: format_sound \ No newline at end of file diff --git a/_sources/api/iblrig.sound.make_sound.rst.txt b/_sources/api/iblrig.sound.make_sound.rst.txt new file mode 100644 index 000000000..620650d85 --- /dev/null +++ b/_sources/api/iblrig.sound.make_sound.rst.txt @@ -0,0 +1,6 @@ +iblrig.sound.make\_sound +======================== + +.. currentmodule:: iblrig.sound + +.. autofunction:: make_sound \ No newline at end of file diff --git a/_sources/api/iblrig.sound.rst.txt b/_sources/api/iblrig.sound.rst.txt new file mode 100644 index 000000000..d3b4434bc --- /dev/null +++ b/_sources/api/iblrig.sound.rst.txt @@ -0,0 +1,15 @@ +iblrig.sound +============ + +.. automodule:: iblrig.sound + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + configure_sound_card + format_sound + make_sound + \ No newline at end of file diff --git a/_sources/api/iblrig.tools.ANSI.rst.txt b/_sources/api/iblrig.tools.ANSI.rst.txt new file mode 100644 index 000000000..37f5e8b42 --- /dev/null +++ b/_sources/api/iblrig.tools.ANSI.rst.txt @@ -0,0 +1,13 @@ +iblrig.tools.ANSI +================= + +.. currentmodule:: iblrig.tools + +.. inheritance-diagram:: ANSI + :parts: 1 + +| + +.. autoclass:: ANSI + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.tools.alyx_reachable.rst.txt b/_sources/api/iblrig.tools.alyx_reachable.rst.txt new file mode 100644 index 000000000..f46bd56c4 --- /dev/null +++ b/_sources/api/iblrig.tools.alyx_reachable.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.alyx\_reachable +============================ + +.. currentmodule:: iblrig.tools + +.. autofunction:: alyx_reachable \ No newline at end of file diff --git a/_sources/api/iblrig.tools.ask_user.rst.txt b/_sources/api/iblrig.tools.ask_user.rst.txt new file mode 100644 index 000000000..3252f357f --- /dev/null +++ b/_sources/api/iblrig.tools.ask_user.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.ask\_user +====================== + +.. currentmodule:: iblrig.tools + +.. autofunction:: ask_user \ No newline at end of file diff --git a/_sources/api/iblrig.tools.call_bonsai.rst.txt b/_sources/api/iblrig.tools.call_bonsai.rst.txt new file mode 100644 index 000000000..0284992bf --- /dev/null +++ b/_sources/api/iblrig.tools.call_bonsai.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.call\_bonsai +========================= + +.. currentmodule:: iblrig.tools + +.. autofunction:: call_bonsai \ No newline at end of file diff --git a/_sources/api/iblrig.tools.call_bonsai_async.rst.txt b/_sources/api/iblrig.tools.call_bonsai_async.rst.txt new file mode 100644 index 000000000..381cbceb2 --- /dev/null +++ b/_sources/api/iblrig.tools.call_bonsai_async.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.call\_bonsai\_async +================================ + +.. currentmodule:: iblrig.tools + +.. autofunction:: call_bonsai_async \ No newline at end of file diff --git a/_sources/api/iblrig.tools.get_anydesk_id.rst.txt b/_sources/api/iblrig.tools.get_anydesk_id.rst.txt new file mode 100644 index 000000000..989fd84a5 --- /dev/null +++ b/_sources/api/iblrig.tools.get_anydesk_id.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.get\_anydesk\_id +============================= + +.. currentmodule:: iblrig.tools + +.. autofunction:: get_anydesk_id \ No newline at end of file diff --git a/_sources/api/iblrig.tools.get_inheritors.rst.txt b/_sources/api/iblrig.tools.get_inheritors.rst.txt new file mode 100644 index 000000000..ebbb99b48 --- /dev/null +++ b/_sources/api/iblrig.tools.get_inheritors.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.get\_inheritors +============================ + +.. currentmodule:: iblrig.tools + +.. autofunction:: get_inheritors \ No newline at end of file diff --git a/_sources/api/iblrig.tools.get_lab_location_dict.rst.txt b/_sources/api/iblrig.tools.get_lab_location_dict.rst.txt new file mode 100644 index 000000000..3a3617ab1 --- /dev/null +++ b/_sources/api/iblrig.tools.get_lab_location_dict.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.get\_lab\_location\_dict +===================================== + +.. currentmodule:: iblrig.tools + +.. autofunction:: get_lab_location_dict \ No newline at end of file diff --git a/_sources/api/iblrig.tools.internet_available.rst.txt b/_sources/api/iblrig.tools.internet_available.rst.txt new file mode 100644 index 000000000..68dde7242 --- /dev/null +++ b/_sources/api/iblrig.tools.internet_available.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.internet\_available +================================ + +.. currentmodule:: iblrig.tools + +.. autofunction:: internet_available \ No newline at end of file diff --git a/_sources/api/iblrig.tools.rst.txt b/_sources/api/iblrig.tools.rst.txt new file mode 100644 index 000000000..2cf76bc7d --- /dev/null +++ b/_sources/api/iblrig.tools.rst.txt @@ -0,0 +1,30 @@ +iblrig.tools +============ + +.. automodule:: iblrig.tools + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + alyx_reachable + ask_user + call_bonsai + call_bonsai_async + get_anydesk_id + get_inheritors + get_lab_location_dict + internet_available + static_vars + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + ANSI + \ No newline at end of file diff --git a/_sources/api/iblrig.tools.static_vars.rst.txt b/_sources/api/iblrig.tools.static_vars.rst.txt new file mode 100644 index 000000000..723c9a4db --- /dev/null +++ b/_sources/api/iblrig.tools.static_vars.rst.txt @@ -0,0 +1,6 @@ +iblrig.tools.static\_vars +========================= + +.. currentmodule:: iblrig.tools + +.. autofunction:: static_vars \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.BehaviorCopier.rst.txt b/_sources/api/iblrig.transfer_experiments.BehaviorCopier.rst.txt new file mode 100644 index 000000000..b3385df64 --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.BehaviorCopier.rst.txt @@ -0,0 +1,13 @@ +iblrig.transfer\_experiments.BehaviorCopier +=========================================== + +.. currentmodule:: iblrig.transfer_experiments + +.. inheritance-diagram:: BehaviorCopier + :parts: 1 + +| + +.. autoclass:: BehaviorCopier + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.CopyState.rst.txt b/_sources/api/iblrig.transfer_experiments.CopyState.rst.txt new file mode 100644 index 000000000..0953a109a --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.CopyState.rst.txt @@ -0,0 +1,13 @@ +iblrig.transfer\_experiments.CopyState +====================================== + +.. currentmodule:: iblrig.transfer_experiments + +.. inheritance-diagram:: CopyState + :parts: 1 + +| + +.. autoclass:: CopyState + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.EphysCopier.rst.txt b/_sources/api/iblrig.transfer_experiments.EphysCopier.rst.txt new file mode 100644 index 000000000..32a620f87 --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.EphysCopier.rst.txt @@ -0,0 +1,13 @@ +iblrig.transfer\_experiments.EphysCopier +======================================== + +.. currentmodule:: iblrig.transfer_experiments + +.. inheritance-diagram:: EphysCopier + :parts: 1 + +| + +.. autoclass:: EphysCopier + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.SessionCopier.rst.txt b/_sources/api/iblrig.transfer_experiments.SessionCopier.rst.txt new file mode 100644 index 000000000..283255b4d --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.SessionCopier.rst.txt @@ -0,0 +1,13 @@ +iblrig.transfer\_experiments.SessionCopier +========================================== + +.. currentmodule:: iblrig.transfer_experiments + +.. inheritance-diagram:: SessionCopier + :parts: 1 + +| + +.. autoclass:: SessionCopier + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.VideoCopier.rst.txt b/_sources/api/iblrig.transfer_experiments.VideoCopier.rst.txt new file mode 100644 index 000000000..b98edc640 --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.VideoCopier.rst.txt @@ -0,0 +1,13 @@ +iblrig.transfer\_experiments.VideoCopier +======================================== + +.. currentmodule:: iblrig.transfer_experiments + +.. inheritance-diagram:: VideoCopier + :parts: 1 + +| + +.. autoclass:: VideoCopier + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.copy_folders.rst.txt b/_sources/api/iblrig.transfer_experiments.copy_folders.rst.txt new file mode 100644 index 000000000..9befa795e --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.copy_folders.rst.txt @@ -0,0 +1,6 @@ +iblrig.transfer\_experiments.copy\_folders +========================================== + +.. currentmodule:: iblrig.transfer_experiments + +.. autofunction:: copy_folders \ No newline at end of file diff --git a/_sources/api/iblrig.transfer_experiments.rst.txt b/_sources/api/iblrig.transfer_experiments.rst.txt new file mode 100644 index 000000000..76034656b --- /dev/null +++ b/_sources/api/iblrig.transfer_experiments.rst.txt @@ -0,0 +1,26 @@ +iblrig.transfer\_experiments +============================ + +.. automodule:: iblrig.transfer_experiments + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + copy_folders + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + BehaviorCopier + CopyState + EphysCopier + SessionCopier + VideoCopier + \ No newline at end of file diff --git a/_sources/api/iblrig.upgrade_iblrig.call_subprocesses.rst.txt b/_sources/api/iblrig.upgrade_iblrig.call_subprocesses.rst.txt new file mode 100644 index 000000000..3ded9b46d --- /dev/null +++ b/_sources/api/iblrig.upgrade_iblrig.call_subprocesses.rst.txt @@ -0,0 +1,6 @@ +iblrig.upgrade\_iblrig.call\_subprocesses +========================================= + +.. currentmodule:: iblrig.upgrade_iblrig + +.. autofunction:: call_subprocesses \ No newline at end of file diff --git a/_sources/api/iblrig.upgrade_iblrig.rst.txt b/_sources/api/iblrig.upgrade_iblrig.rst.txt new file mode 100644 index 000000000..b4cca2f4f --- /dev/null +++ b/_sources/api/iblrig.upgrade_iblrig.rst.txt @@ -0,0 +1,14 @@ +iblrig.upgrade\_iblrig +====================== + +.. automodule:: iblrig.upgrade_iblrig + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + call_subprocesses + upgrade + \ No newline at end of file diff --git a/_sources/api/iblrig.upgrade_iblrig.upgrade.rst.txt b/_sources/api/iblrig.upgrade_iblrig.upgrade.rst.txt new file mode 100644 index 000000000..23a1dbd9d --- /dev/null +++ b/_sources/api/iblrig.upgrade_iblrig.upgrade.rst.txt @@ -0,0 +1,6 @@ +iblrig.upgrade\_iblrig.upgrade +============================== + +.. currentmodule:: iblrig.upgrade_iblrig + +.. autofunction:: upgrade \ No newline at end of file diff --git a/_sources/api/iblrig.valve.Valve.rst.txt b/_sources/api/iblrig.valve.Valve.rst.txt new file mode 100644 index 000000000..2201e77c4 --- /dev/null +++ b/_sources/api/iblrig.valve.Valve.rst.txt @@ -0,0 +1,13 @@ +iblrig.valve.Valve +================== + +.. currentmodule:: iblrig.valve + +.. inheritance-diagram:: Valve + :parts: 1 + +| + +.. autoclass:: Valve + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.valve.ValveValues.rst.txt b/_sources/api/iblrig.valve.ValveValues.rst.txt new file mode 100644 index 000000000..2db928d8d --- /dev/null +++ b/_sources/api/iblrig.valve.ValveValues.rst.txt @@ -0,0 +1,13 @@ +iblrig.valve.ValveValues +======================== + +.. currentmodule:: iblrig.valve + +.. inheritance-diagram:: ValveValues + :parts: 1 + +| + +.. autoclass:: ValveValues + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig.valve.rst.txt b/_sources/api/iblrig.valve.rst.txt new file mode 100644 index 000000000..3d6a25c36 --- /dev/null +++ b/_sources/api/iblrig.valve.rst.txt @@ -0,0 +1,15 @@ +iblrig.valve +============ + +.. automodule:: iblrig.valve + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Valve + ValveValues + \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.call_git.rst.txt b/_sources/api/iblrig.version_management.call_git.rst.txt new file mode 100644 index 000000000..71b707354 --- /dev/null +++ b/_sources/api/iblrig.version_management.call_git.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.call\_git +==================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: call_git \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.check_for_updates.rst.txt b/_sources/api/iblrig.version_management.check_for_updates.rst.txt new file mode 100644 index 000000000..0b685add6 --- /dev/null +++ b/_sources/api/iblrig.version_management.check_for_updates.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.check\_for\_updates +============================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: check_for_updates \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.check_upgrade_prerequisites.rst.txt b/_sources/api/iblrig.version_management.check_upgrade_prerequisites.rst.txt new file mode 100644 index 000000000..bfe7db0af --- /dev/null +++ b/_sources/api/iblrig.version_management.check_upgrade_prerequisites.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.check\_upgrade\_prerequisites +======================================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: check_upgrade_prerequisites \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_branch.rst.txt b/_sources/api/iblrig.version_management.get_branch.rst.txt new file mode 100644 index 000000000..00f9fcc13 --- /dev/null +++ b/_sources/api/iblrig.version_management.get_branch.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_branch +====================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_branch \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_changelog.rst.txt b/_sources/api/iblrig.version_management.get_changelog.rst.txt new file mode 100644 index 000000000..452c10dbf --- /dev/null +++ b/_sources/api/iblrig.version_management.get_changelog.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_changelog +========================================= + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_changelog \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_commit_hash.rst.txt b/_sources/api/iblrig.version_management.get_commit_hash.rst.txt new file mode 100644 index 000000000..6e5a7b1a0 --- /dev/null +++ b/_sources/api/iblrig.version_management.get_commit_hash.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_commit\_hash +============================================ + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_commit_hash \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_detailed_version_string.rst.txt b/_sources/api/iblrig.version_management.get_detailed_version_string.rst.txt new file mode 100644 index 000000000..a3be50488 --- /dev/null +++ b/_sources/api/iblrig.version_management.get_detailed_version_string.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_detailed\_version\_string +========================================================= + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_detailed_version_string \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_local_version.rst.txt b/_sources/api/iblrig.version_management.get_local_version.rst.txt new file mode 100644 index 000000000..36d5bbb1d --- /dev/null +++ b/_sources/api/iblrig.version_management.get_local_version.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_local\_version +============================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_local_version \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_remote_tags.rst.txt b/_sources/api/iblrig.version_management.get_remote_tags.rst.txt new file mode 100644 index 000000000..95b7fffb3 --- /dev/null +++ b/_sources/api/iblrig.version_management.get_remote_tags.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_remote\_tags +============================================ + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_remote_tags \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.get_remote_version.rst.txt b/_sources/api/iblrig.version_management.get_remote_version.rst.txt new file mode 100644 index 000000000..ba2bf5099 --- /dev/null +++ b/_sources/api/iblrig.version_management.get_remote_version.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.get\_remote\_version +=============================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: get_remote_version \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.is_dirty.rst.txt b/_sources/api/iblrig.version_management.is_dirty.rst.txt new file mode 100644 index 000000000..26710de10 --- /dev/null +++ b/_sources/api/iblrig.version_management.is_dirty.rst.txt @@ -0,0 +1,6 @@ +iblrig.version\_management.is\_dirty +==================================== + +.. currentmodule:: iblrig.version_management + +.. autofunction:: is_dirty \ No newline at end of file diff --git a/_sources/api/iblrig.version_management.rst.txt b/_sources/api/iblrig.version_management.rst.txt new file mode 100644 index 000000000..93c0045ce --- /dev/null +++ b/_sources/api/iblrig.version_management.rst.txt @@ -0,0 +1,23 @@ +iblrig.version\_management +========================== + +.. automodule:: iblrig.version_management + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + call_git + check_for_updates + check_upgrade_prerequisites + get_branch + get_changelog + get_commit_hash + get_detailed_version_string + get_local_version + get_remote_tags + get_remote_version + is_dirty + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.rst.txt new file mode 100644 index 000000000..38e1d7e58 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_ImagingChoiceWorld +================================================= + +.. automodule:: iblrig_tasks._iblrig_tasks_ImagingChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..955ef639d --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_ImagingChoiceWorld.task.Session +============================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.rst.txt new file mode 100644 index 000000000..66e3b0261 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_ImagingChoiceWorld.task +====================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.rst.txt new file mode 100644 index 000000000..897a04c4a --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_advancedChoiceWorld +================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_advancedChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..1a654959c --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_advancedChoiceWorld.task.Session +=============================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.rst.txt new file mode 100644 index 000000000..abe9d89d5 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_advancedChoiceWorld.task +======================================================= + +.. automodule:: iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.rst.txt new file mode 100644 index 000000000..4dd3ed63f --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_biasedChoiceWorld +================================================ + +.. automodule:: iblrig_tasks._iblrig_tasks_biasedChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..6f42138e1 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_biasedChoiceWorld.task.Session +============================================================= + +.. currentmodule:: iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.rst.txt new file mode 100644 index 000000000..858b45876 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_biasedChoiceWorld.task +===================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.rst.txt new file mode 100644 index 000000000..8c9f15d25 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_ephysChoiceWorld +=============================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_ephysChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..9ef4b2c1a --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_ephysChoiceWorld.task.Session +============================================================ + +.. currentmodule:: iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.rst.txt new file mode 100644 index 000000000..fb6839eeb --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_ephysChoiceWorld.task +==================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.rst.txt new file mode 100644 index 000000000..c153fe226 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_habituationChoiceWorld +===================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_habituationChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..198472ffc --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_habituationChoiceWorld.task.Session +================================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.rst.txt new file mode 100644 index 000000000..3989ca06f --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_habituationChoiceWorld.task +========================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.rst.txt new file mode 100644 index 000000000..9fc728681 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.rst.txt @@ -0,0 +1,17 @@ +iblrig\_tasks.\_iblrig\_tasks\_neuroModulatorChoiceWorld +======================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + + task_validation + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.rst.txt new file mode 100644 index 000000000..a8338b845 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData +=========================================================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task + +.. inheritance-diagram:: NeuroModulatorChoiceTrialData + :parts: 1 + +| + +.. autoclass:: NeuroModulatorChoiceTrialData + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..27727c747 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_neuroModulatorChoiceWorld.task.Session +===================================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.rst.txt new file mode 100644 index 000000000..d6d98b06a --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_neuroModulatorChoiceWorld.task.SessionRelatedBlocks +================================================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task + +.. inheritance-diagram:: SessionRelatedBlocks + :parts: 1 + +| + +.. autoclass:: SessionRelatedBlocks + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.rst.txt new file mode 100644 index 000000000..dff0b1c75 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.rst.txt @@ -0,0 +1,16 @@ +iblrig\_tasks.\_iblrig\_tasks\_neuroModulatorChoiceWorld.task +============================================================= + +.. automodule:: iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + NeuroModulatorChoiceTrialData + Session + SessionRelatedBlocks + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.rst.txt new file mode 100644 index 000000000..560e713a7 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_passiveChoiceWorld +================================================= + +.. automodule:: iblrig_tasks._iblrig_tasks_passiveChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..4ed131ce7 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_passiveChoiceWorld.task.Session +============================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.rst.txt new file mode 100644 index 000000000..774422f22 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_passiveChoiceWorld.task +====================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.rst.txt new file mode 100644 index 000000000..3360f254e --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_spontaneous +========================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_spontaneous + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.rst.txt new file mode 100644 index 000000000..a04fd09c2 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_spontaneous.task.Session +======================================================= + +.. currentmodule:: iblrig_tasks._iblrig_tasks_spontaneous.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.task.rst.txt new file mode 100644 index 000000000..70b4325e9 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_spontaneous.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_spontaneous.task +=============================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_spontaneous.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.rst.txt new file mode 100644 index 000000000..29b0c5523 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingChoiceWorld +================================================== + +.. automodule:: iblrig_tasks._iblrig_tasks_trainingChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..e9021ebc7 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingChoiceWorld.task.Session +=============================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.rst.txt new file mode 100644 index 000000000..27de963f9 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.rst.txt @@ -0,0 +1,6 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingChoiceWorld.task.float\_or\_none +======================================================================= + +.. currentmodule:: iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task + +.. autofunction:: float_or_none \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.rst.txt new file mode 100644 index 000000000..f5dac135d --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.rst.txt @@ -0,0 +1,22 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingChoiceWorld.task +======================================================= + +.. automodule:: iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task + + .. rubric:: Functions + + .. autosummary:: + :nosignatures: + :toctree: + + float_or_none + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.rst.txt new file mode 100644 index 000000000..5ddbb9706 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.rst.txt @@ -0,0 +1,15 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingPhaseChoiceWorld +======================================================= + +.. automodule:: iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + task + diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.rst.txt new file mode 100644 index 000000000..32442d0eb --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.rst.txt @@ -0,0 +1,13 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingPhaseChoiceWorld.task.Session +==================================================================== + +.. currentmodule:: iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task + +.. inheritance-diagram:: Session + :parts: 1 + +| + +.. autoclass:: Session + :members: + :undoc-members: \ No newline at end of file diff --git a/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.rst.txt b/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.rst.txt new file mode 100644 index 000000000..e1e4570a2 --- /dev/null +++ b/_sources/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.rst.txt @@ -0,0 +1,14 @@ +iblrig\_tasks.\_iblrig\_tasks\_trainingPhaseChoiceWorld.task +============================================================ + +.. automodule:: iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task + + .. rubric:: Classes + + .. autosummary:: + :nosignatures: + :toctree: + :template: custom-class-template.rst + + Session + \ No newline at end of file diff --git a/_sources/api/iblrig_tasks.rst.txt b/_sources/api/iblrig_tasks.rst.txt new file mode 100644 index 000000000..1fe2f9423 --- /dev/null +++ b/_sources/api/iblrig_tasks.rst.txt @@ -0,0 +1,24 @@ +iblrig\_tasks +============= + +.. automodule:: iblrig_tasks + +.. rubric:: Modules + +.. autosummary:: + :nosignatures: + :toctree: + :template: custom-module-template.rst + :recursive: + + _iblrig_tasks_advancedChoiceWorld + _iblrig_tasks_biasedChoiceWorld + _iblrig_tasks_ephysChoiceWorld + _iblrig_tasks_habituationChoiceWorld + _iblrig_tasks_ImagingChoiceWorld + _iblrig_tasks_neuroModulatorChoiceWorld + _iblrig_tasks_passiveChoiceWorld + _iblrig_tasks_spontaneous + _iblrig_tasks_trainingChoiceWorld + _iblrig_tasks_trainingPhaseChoiceWorld + diff --git a/_sources/changelog.rst.txt b/_sources/changelog.rst.txt new file mode 100644 index 000000000..9f448a2b9 --- /dev/null +++ b/_sources/changelog.rst.txt @@ -0,0 +1,2 @@ +.. include:: ../../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/_sources/faq.rst.txt b/_sources/faq.rst.txt new file mode 100644 index 000000000..8a98a9134 --- /dev/null +++ b/_sources/faq.rst.txt @@ -0,0 +1,123 @@ +************************** +Frequently Asked Questions +************************** + +Here we collect common issues and questions regarding IBLRIG. + +First Aid +========= + +If your rig is acting up: + +* Employ the **automated test-script** bundled with IBLRIG. This script helps identify common configuration issues. + Execute it using PowerShell: + + .. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + validate_iblrig + +* Check `the comprehensive user manual `__ ("Appendix 3" on GoogleDrive). + Verify if all connections are secure, and configurations align with the manual's guidelines. + +* Don't hesitate to **contact our developer team** for assistance. We're committed to getting your system back on track. + + +Bug Reports & Feature Requests +============================== + +IBLRIG remains in dynamic development. Your input is invaluable in shaping its direction. `Send us your +bug reports and feature-requests via GitHub `_ - we will do our best to help you. + + +Sound Issues +============ + +* Double-check all wiring for loose connections. + +* Is ``hardware_settings.yaml`` set up correctly? Valid options for sound ``OUTPUT`` are: + + - ``hifi``, + - ``harp``, + - ``xonar``, or + - ``sysdefault``. + + Make sure that this value matches the actual soundcard used on your rig. + Note that ``sysdefault`` is only used in test scenarios and should not be used during actual experiments. + + +Screen Issues +============= + +General +^^^^^^^ + +* The ribbon cable attaching the screen to the driver board is notoriously finicky. If you are having brightness issues or do not have a signal, try gently repositioning this cable and ensure it is tightly seated in its connection. +* Screen and ribbon cable can be easily damaged. It is useful to have backup at hand. +* Screen flashing can occur if the power supply does not match the screen specifications. Use a 12V adapter with at least 1A. +* If the Bonsai display is appearing on the PC screen when a task starts, try unplugging the rig screen, rebooting and plugging the screen back in. Other variations of screen unplugging and rebooting may also work. + Also make sure, that the ``DISPLAY_IDX`` value in ``hardware_settings.yaml`` is set correctly. + +Defining Default Position & Size of Bonsai Visualizers +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Is the preview window of the video recording showing on the iPad screen instead of the computer's main display during a +session? To redefine the default position and size of the Bonsai visualizer: + +#. Open the Bonsai executable distributed with IBLRIG: ``C:\iblrigv8\Bonsai\Bonsai.exe``. +#. Open the respective Bonsai workflow: + + .. code:: + + C:\iblrigv8\devices\camera_recordings\TrainingRig_SaveVideo_TrainingTasks.bonsai + +#. Start the workflow by clicking on the play-button. +#. Adjust the position and size of the windows as per your preference. +#. Stop the workflow. +#. Save the workflow. + + +Camera Issues +============= + +* If a camera is not detected by the computer or causes intermittent issues it might be an issue with the USB connection. + + * Ensure that the camera is connected to the computer on a USB3 port (usually indicated by a blue plastic tab in the port). + USB2 (black tabs) neither provides the necessary transfer rates nor sufficient current to power the camera. + * Use the `original USB3.1 cable `_ provided by FLIR. + It comes in 3 m or 5 m - stick with the shorter version if possible. + * Try to avoid USB extensions. + The original cable (see above) should be sufficiently long in most situations. + * Ideally, use one of the onboard USB3 ports of your computer facing to the back of the machine. + Front-facing ports may not be able to provide enough power. + * If you use a USB 3.1 Host Controller Card check if it requires additional powering through a SATA or Molex cable. + FLIR offers `a few models `_ that should work fine. + + +Frame2TTL +========= + +* Version 1 of Frame2TTL won't be detected after restarting the computer. + Unplugging and replugging the USB cable should make it responsive again. +* If IBLRIG complains about not receiving any TTL signals from Frame2TTL: + + * Ensure Frame2TTL's sensor is positioned over the bottom-right corner of the rig's screen. + Secure the sensor's cable to the screen mount with a zip-tie to prevent it from slipping off the screen. + Additionally, use a piece of electrical tape to hold the sensor in place. + + * Verify that the sensor is connected to Frame2TTL with the correct polarity + + * Version 1: GND = black cable, SIG = white cable + * Version 2 and 3: BLK = black cable, WHT = white cable + * Ensure that Frame2TTL's TTL Output is plugged into Bpod's TTL Input #1. + Note that versions 2 and 3 of Frame2TTL have a second BNC output labeled "analog" - this is *not* the TTL output. + * Recalibrate Frame2TTL using the calibration routine in IBLRIG's Tools menu and check for any errors. + +* If the above steps do not resolve the issue, try the following: + + #. Swap out the BNC cable between Frame2TTL and Bpod. + Use a single cable without any branches. + #. Connect an oscilloscope to the Bpod end of the cable and run a calibration. + Look for a voltage step in Frame2TTL's output when the calibration routine switches from dark to light. + #. If you *do* see the change in the TTL signal, the Bpod might be faulty. Try using a different Bpod unit. + #. If you do *not* see the voltage step, the Frame2TTL might be faulty. Try using a different Frame2TTL unit. diff --git a/_sources/hardware.rst.txt b/_sources/hardware.rst.txt new file mode 100644 index 000000000..d3f19db12 --- /dev/null +++ b/_sources/hardware.rst.txt @@ -0,0 +1,94 @@ +Hardware Guide +============== + + +Upgrading Xonar AE to Bpod HiFi Module +------------------------------------------------ + +.. note:: The following guide only concerns behavior rigs using `Asus Xonar AE` sound cards. + The `Harp` sound cards used in our Ephys and Mesoscope rigs work fine and do not require replacing! + +Background +"""""""""" + +In their original design, IBL’s behavioral training rigs relied on a consumer-grade sound-card - the `ASUS Xonar AE `_ - for delivering auditory cues to the subject. We have identified the Xonar AE as a weak point in the design of the training rig as this choice of hardware has several severe drawbacks: + +* Synchronization between individual components of the rig relies on TTL Signals, a standardized way of communicating between digital devices. + With the Xonar sound-card, we emulate TTL pulses on one of the soundcard’s analog audio outputs. + The resulting signal does not conform well to the TTL standard since (a) we cannot guarantee the required signal rise-times, and (b) pulse-amplitude depends on the computer’s audio volume and impedance settings. The effects are increased latencies and accidental misconfigurations. + The latter have the potential to cause synchronization issues and more problems further down the pipeline. +* The ASUS Xonar AE does not seem to be a particularly robust piece of equipment - we’ve experienced several catastrophic failures across our rigs at IBL. Replacement hardware is increasingly hard to come by as the Asus Xonar AE is not being produced anymore. +* The soundcard’s driver has been causing issues with specific Windows updates that require manual intervention / rollback of the respective updates. +* There is no Windows 11 specific driver available. + +For these reasons, we decided to replace the Xonar AE with the `Bpod HiFi Module HD `_ by Sanworks: +The HiFi Module is capable of delivering high fidelity sound stimuli at low latencies, supports proper TTL signaling as well as serial communication with the Bpod Finite State Machine and does not require any dedicated drivers. +The upgrade procedure is straightforward and should take no longer than 5-10 minutes. + +Requirements +"""""""""""" + +To replace your existing Xonar AE with the Bpod HiFi Module HD you will require the following: + +* 1x Bpod HiFi Module HD +* 1x Micro-USB to USB-A cable +* 1x Ethernet cable (RJ45) +* 1x RCA to 3.5 mm audio adapter +* 1x 3 mm flathead screwdriver + +.. warning:: Support for the Bpod HiFi Module was introduced with IBLRIG 8.16.0 and will not be backported to older version of IBLRIG. + Make sure to upgrade to the latest version of IBLRIG before continuing with this guide. + +Upgrade Procedure +""""""""""""""""" + +1. Use the 3 mm flathead screwdriver to unscrew the BNC to wire adapter from the amplifier board. + While the adapter itself is not needed anymore we will continue using the BNC cable. + Leave the other end of the BNC cable plugged into the Bpod as it is. + + .. figure:: img/amp2x15_labels.png + :width: 100% + :class: with-border + + Disconnect the BNC to wire adapter from the amplifier board. + +2. Unplug the 3.5 mm audio cable from the Xonar AE sound card on the backside of the rig's computer. + Leave the other end of the 3.5 mm audio cable connected to the amplifier board. + + .. figure:: img/xonar_labels.png + :width: 100% + :class: with-border + + Unplug the 3.5 mm audio cable from the Xonar AE sound card. + +3. Connect the Bpod HiFi Module as follows: + + * the BNC cable connects to TTL In 2 of the Bpod (cf. step 1), + * the 3.5 mm audio cable connects to the amplifier board via the RCA adapter (cf. step 2), + * the USB cable connects to the rig's computer + * the Ethernet cable connects to one of the Bpod's Module ports. + Warning: Bpod uses identical connectors for its Behavior ports - do not mix them up! + + .. figure:: img/hifi_labels.png + :width: 100% + :class: with-border + + The Bpod HiFi Modules and its connections. + +4. Open `C:/iblrigv8/settings/hardware_settings.yaml` in a text-editor. + Find the section `device_sound` and adapt it as follows: + + .. code-block:: yaml + + device_sound: + OUTPUT: hifi + COM_SOUND: COMx # replace with the HiFi Module's actual COM port! + AMP_TYPE: AMP2X15 + + .. tip:: + + Use Windows' device manager to identify the HiFi Module's COM port. + The device should show up in the section labelled "Ports (COM & LPT)" after plugging it in. + +5. Start IBLRIG and make sure that the hardware validation during start-up does not find any issues. + Finally, start a session and verify that you can hear the audio cues. \ No newline at end of file diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 000000000..382286582 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,30 @@ +.. if-builder:: html + + .. include:: ../../README.md + :parser: myst_parser.sphinx_ + +.. toctree:: + :maxdepth: 3 + :hidden: + + installation + usage + reference + hardware + reference_developer_guide + faq + +.. if-builder:: html + + .. toctree:: + :hidden: + + api + changelog + + .. toctree:: + :caption: Links + :hidden: + + IBLRIG on GitHub + Appendix 3: IBL protocol for setting up the behavioral training rig diff --git a/_sources/installation.rst.txt b/_sources/installation.rst.txt new file mode 100644 index 000000000..efba77d19 --- /dev/null +++ b/_sources/installation.rst.txt @@ -0,0 +1,264 @@ +Installation guide +================== + +.. prerequisites:: + + * A computer running Windows 10 or 11, + * A working installation of `git for windows `_, and + * `Notepad++ `_ or some other decent text editor. + +.. tip:: + + iblrigv8 can be installed alongside older versions of iblrig without affecting the latter. + +.. tip:: + + If you believe this guide is incomplete or requires improvements, please don't hesitate to reach out and + :ref:`submit a bug report`. + + +Preparing Windows PowerShell +---------------------------- + +Open Windows PowerShell in administrator mode: + +* Click on the Windows Start button or press the Windows key on your keyboard. +* Type "PowerShell" into the search bar. +* You should see "Windows PowerShell" or "PowerShell" in the search results. +* Right-click on it. +* In the context menu that appears, select "Run as administrator." + +Now, run the following command at the prompt of Windows PowerShell: + +.. code-block:: powershell + + Set-ExecutionPolicy RemoteSigned -Force + +.. tip:: + + Keep the Administrator PowerShell open for the next step. + +.. admonition:: Background + :class: seealso + + In PowerShell, there are execution policies that determine the level of security for running scripts. The default execution + policy is often set to ``Restricted``, which means that scripts are not allowed to run. However, to install Python or run + certain scripts, you need to adjust the execution policy. By setting the execution policy to ``RemoteSigned``, you are + allowing the execution of locally created scripts without any digital signature while requiring that remotely downloaded + scripts (from the internet) must be digitally signed by a trusted source to run. This strikes a balance between security + and usability. + + +Installing Visual C++ Redistributable +------------------------------------- + +With the Administrator PowerShell still open, run the following commands: + +.. code-block:: powershell + + New-Item -ItemType Directory -Force -Path C:\Temp + Invoke-WebRequest -Uri https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe -OutFile C:\Temp\vcredist_x64.exe + Start-Process -NoNewWindow -Wait -FilePath C:\Temp\vcredist_x64.exe -ArgumentList "/install", "/quiet", "/norestart" + Invoke-WebRequest -Uri https://aka.ms/vs/17/release/vc_redist.x64.exe -OutFile C:\Temp\vc_redist.x64.exe + Start-Process -NoNewWindow -Wait -FilePath C:\Temp\vc_redist.x64.exe -ArgumentList "/install", "/quiet", "/norestart" + +.. warning:: Make sure you exit the Administrator PowerShell before continuing with the next steps! + +.. admonition:: Background + :class: seealso + + These commands will create a temporary directory, download and install the Visual C++ Redistributable package for + 64-bit Windows systems. The installer is retrieved from a Microsoft server and executed with parameters to ensure a seamless + and unobtrusive installation process. + + +Installing Python 3.10 +---------------------- + +Open a `new` Windows Powershell prompt (no administrator mode) and run the following: + +.. code-block:: powershell + + New-Item -ItemType Directory -Force -Path C:\Temp + Invoke-WebRequest -Uri https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe -OutFile C:\Temp\python-3.10.11-amd64.exe + Start-Process -NoNewWindow -Wait -FilePath C:\Temp\python-3.10.11-amd64.exe -ArgumentList "/passive", "InstallAllUsers=0", "Include_launcher=0", "Include_test=0" + +Check that everything worked by running the following command: + +.. code-block:: powershell + + &$env:UserProfile\AppData\Local\Programs\Python\Python310\python.exe --version + +The command should return ``Python 3.10.11`` + + +.. admonition:: Background + :class: seealso + + These commands will create a temporary directory, download the Python installer from a specific URL, and then execute the + installer with specific installation options, all in a controlled and automated manner. + + +Installing iblrigv8 +------------------- + +1. From the Powershell command line, clone the `iblrigv8` branch of iblrig to ``C:\iblrigv8``: + + .. code-block:: powershell + + git clone -b iblrigv8 https://github.com/int-brain-lab/iblrig.git C:\iblrigv8 + + +2. Install a new virtual environment and update pip: + + .. code-block:: powershell + + &$env:UserProfile\AppData\Local\Programs\Python\Python310\python.exe -m venv C:\iblrigv8\venv + C:\iblrigv8\venv\scripts\python.exe -m pip install --upgrade pip wheel + + +3. Install iblrig in editable mode: + + .. code-block:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + cd C:\iblrigv8 + pip install -e . + + +4. Install Spinnaker SDK and PySpin: + + .. code-block:: powershell + + install_spinnaker + install_pyspin + + +5. Install Bonsai in portable mode: + + .. code-block:: powershell + + cd C:\iblrigv8\Bonsai + powershell.exe .\install.ps1 + cd .. + + +6. Install additional tasks and extractors for personal projects (optional): + + .. code-block:: powershell + + git clone https://github.com/int-brain-lab/project_extraction.git C:\project_extraction + cd C:\project_extraction + pip install -e . + + +7. Continue with :ref:`the next section`. + + +Configuration Instructions +-------------------------- + +Rig Configuration Files +~~~~~~~~~~~~~~~~~~~~~~~ + +Copy the template settings files: + +.. code-block:: + + cd C:\iblrigv8\settings + cp hardware_settings_template.yaml hardware_settings.yaml + cp iblrig_settings_template.yaml iblrig_settings.yaml + explorer C:\iblrigv8\settings + + +Update the two settings files using a text-editor: + +* ``iblrig_settings.yaml`` +* ``hardware_settings.yaml`` + +If the computer has been used with IBLRIG version 7 or earlier, the correct values can likely be found in ``C:\iblrig_params\ +.iblrig_params.json``. + + +Setting up ONE +~~~~~~~~~~~~~~ + + +Setup ONE to connect to https://alyx.internationalbrainlab.org, you will need your Alyx username and password. + +See instructions for that here: https://int-brain-lab.github.io/iblenv/notebooks_external/one_quickstart.html + + +.. exercise:: Make sure you can connect to Alyx ! + + Open a Python shell in the environment and connect to Alyx (you may have to setup ONE) + + .. code-block:: + + C:\iblrigv8\venv\scripts\Activate.ps1 + ipython + + Then at the IPython prompt + + .. code-block:: python + + from one.api import ONE + one = ONE(username='your_username', password='your_password', base_url='https://alyx.internationalbrainlab.org') + + +.. exercise:: You can check that everything went fine by running the test suite: + + .. code-block:: powershell + + cd C:\iblrigv8 + python -m unittest discover + + The tests should pass to completion after around 40 seconds + + +Updating iblrigv8 +----------------- + +To update iblrigv8 to the newest version: + +.. code-block:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + cd C:\iblrigv8 + git pull + pip install --upgrade -e . + + +To update the additional tasks and extractors (see :ref:`Installing iblrigv8`, point 5): + +.. code-block:: powershell + + cd C:\project_extraction + git pull + + +.. tip:: + + While usually quite snappy, upgrading the virtual environment in some instances can take longer than expected. + Please be patient during the upgrade procedure. + + +Switch to specific iblrig version +--------------------------------- +.. warning:: Downgrading is not recommended and may not work as some releases break compatibility with earlier versions. + +First fetch all available version tags and list them: + +.. code-block:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + cd C:\iblrigv8 + git fetch --all --tags --prune + git tag --list '8.*' + +Then switch to the desired version, for example `8.15.5`: + +.. code-block:: powershell + + git checkout tag/8.15.5 + pip install --upgrade -e . diff --git a/_sources/reference.rst.txt b/_sources/reference.rst.txt new file mode 100644 index 000000000..64ed18a02 --- /dev/null +++ b/_sources/reference.rst.txt @@ -0,0 +1,8 @@ +************************************ +Reference +************************************ + +.. include:: reference_description_file.rst +.. include:: reference_task_qc.rst +.. include:: reference_write_your_own_task.rst +#.. include:: reference_developer_guide.rst diff --git a/_sources/reference_description_file.rst.txt b/_sources/reference_description_file.rst.txt new file mode 100644 index 000000000..121150739 --- /dev/null +++ b/_sources/reference_description_file.rst.txt @@ -0,0 +1,215 @@ +Describing an Experiment +======================== + +Experiment description file +--------------------------- + +All experiments are described by a file with the name +``_ibl_experiment.description.yaml``. This description file contains +details about the experiment such as, information about the devices used +to collect data, or the behavior tasks run during the experiment. The +content of this file is used to copy data from the acquisition computer +to the lab server and also determines the task pipeline that will be +used to extract the data on the lab servers. It’s accuracy in fully +describing the experiment is, therefore, very important! + +Here is an example of a complete experiment description file for a +mesoscope experiment running two consecutive tasks, +``biasedChoiceWorld`` followed by ``passiveChoiceWorld``. + +.. code:: yaml + + devices: + mesoscope: + mesoscope: + collection: raw_imaging_data* + sync_label: chrono + cameras: + belly: + collection: raw_video_data + sync_label: audio + width: 640 + height: 512 + fps: 30 + left: + collection: raw_video_data + sync_label: audio + right: + collection: raw_video_data + sync_label: audio + procedures: + - Imaging + projects: + - ibl_mesoscope_active + sync: + nidq: + acquisition_software: timeline + collection: raw_sync_data + extension: npy + tasks: + - _biasedChoiceWorld: + collection: raw_task_data_00 + sync_label: bpod + extractors: [TrialRegisterRaw, ChoiceWorldTrialsTimeline, TrainingStatus] + - passiveChoiceWorld: + collection: raw_task_data_01 + sync_label: bpod + extractors: [PassiveRegisterRaw, PassiveTaskTimeline] + version: 1.0.0 + +Breaking down the components of an experiment description file +-------------------------------------------------------------- + +Devices +~~~~~~~ + +The devices section in the experiment description file lists the set of +devices from which data was collection in the experiment. Supported +devices are Cameras, Microphone, Mesoscope, Neuropixel, Photometry and +Widefield. + +The convention for this section is to have the device name followed by a +list of sub-devices, e.g. + +.. code:: yaml + + devices: + cameras: + belly: + collection: raw_video_data + sync_label: audio + width: 640 + height: 512 + fps: 30 + left: + collection: raw_video_data + sync_label: audio + right: + collection: raw_video_data + sync_label: audio + +In the above example, ``cameras`` is the device and the sub-devices are +``belly``, ``left`` and ``right``. + +If there are no sub-devices, the sub-device is given the same name as +the device, e.g. + +.. code:: yaml + + devices: + mesoscope: + mesoscope: + collection: raw_imaging_data* + sync_label: chrono + +Each sub-device must have at least the following two keys - +**collection** - the folder containing the data - **sync_label** - the +name of the common ttl pulses in the channel map used to sync the +timestamps + +Additional keys can also be specified for specific extractors, e.g. for +the belly camera the camera metadata passed into the camera extractor +task is defined in this file. + +Procedures +~~~~~~~~~~ + +The procedures section lists the set of procedures that apply to this +experiment. The list of possible procedures can be found +`here `__. + +As many procedure that apply to the experiment can be added e.g. + +.. code:: yaml + + procedures: + - Fiber photometry + - Optical stimulation + - Ephys recording with acute probe(s) + +Projects +~~~~~~~~ + +The projects section lists the set of projects that apply to this +experiment. The list of possible projects can be found +`here `__. + +As many projects that apply to the experiment can be added e.g. + +:: + + projects: + - ibl_neuropixel_brainwide_01 + - carandiniharris_midbrain_ibl + +Sync +~~~~ + +The sync section contains information about the device used to collect +the syncing data and the format of the data. Supported sync devices are +bpod, nidq, tdms, timeline. Only **one** sync device can be specified +per experiment description file and act as the main clock to which other +timeseries are synced. + +An example of an experiment run with bpod as the main syncing device is, + +.. code:: yaml + + sync: + bpod: + collection: raw_behavior_data + extension: bin + +Another example for spikeglx electrophysiology recordings with +Neuropixel 1B probes use the nidq as main synchronisation. + +.. code:: yaml + + sync: + nidq: + collection: raw_ephys_data + extension: bin + acquisition_software: spikeglx + +Each sync device must have at least the following two keys - +**collection** - the folder containing the data - **extension** - the +file extension of the sync data + +Optional keys include, for example ``acquisition_software``, the +software used to acquire the sync pulses + +Tasks +~~~~~ + +The tasks section contains a list of the behavioral protocols run during +the experiment. The name of the protocol must be given in the list e.g. + +.. code:: yaml + + tasks: + - _biasedChoiceWorld: + collection: raw_task_data_00 + sync_label: bpod + extractors: [TrialRegisterRaw, ChoiceWorldTrialsTimeline, TrainingStatus] + - passiveChoiceWorld: + collection: raw_task_data_01 + sync_label: bpod + extractors: [PassiveRegisterRaw, PassiveTaskTimeline] + +Each task must have at least the following two keys - **collection** - +the folder containing the data - **sync_label** - the name of the common +ttl pulses in the channel map used to sync the timestamps + +The ``collection`` must be unique for each task. i.e. Data from two +tasks cannot be stored in the same folder. + +If the Tasks used to extract the data are not the default tasks, the +extractors to use must be passed in as an additional key. The order of +the extractors defines their parent child relationship in the task +architecture. + +Version +~~~~~~~ + +The version section gives version number of the experiment description +file diff --git a/_sources/reference_developer_guide.rst.txt b/_sources/reference_developer_guide.rst.txt new file mode 100644 index 000000000..a5a6e24db --- /dev/null +++ b/_sources/reference_developer_guide.rst.txt @@ -0,0 +1,142 @@ +Developer Guide +=============== + + +Versioning Scheme +----------------- + +IBLRIG v8 uses `Semantic Versioning `_. +Its version string (currently "|version|") is a combination of three fields, separated by dots: + +.. centered:: ``MAJOR`` . ``MINOR`` . ``PATCH`` + +* The ``MAJOR`` field is only incremented for breaking changes, i.e., changes that are not backward compatible with previous changes. + Releases of IBLRIG v8, for instance, are generally incompatible with IBLRIG v7. +* The ``MINOR`` field will be incremented upon adding new, backwards compatible features. +* The ``PATCH`` field will be incremented with each new, backwards compatible bugfix release that does not implement a new feature. + +On the developer side, these 3 fields are manually controlled by, both + + 1. adjusting the variable ``__version__`` in ``iblrig/__init__.py``, and + 2. adding the corresponding version string to a commit as a `git tag `_, + for instance: + + .. code-block:: console + + git tag 8.8.4 + git push origin --tags + +The version string displayed by IBLRIG *may* include additional fields, such as in "|version|.post3+dirty". +Here, + +* ``post3`` indicates the third unversioned commit after the latest versioned release, and +* ``dirty`` indicates the presence of uncommited changes in your local repository of IBLRIG. + +Both of these fields are automatically inferred (by means of ``git describe``) and do not require manual interaction from the +developer. + + +Package Management and Development Workflows with PDM +----------------------------------------------------- + +We use `PDM `_ to manage dependencies of IBLRIG. +PDM can also be used to run various commands with relevance to the development process without having to activate a virtual +environment first. +Please refer to `PDM's documentation `_ for help with installing PDM. + + +Installing Developer Dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To install additional dependencies needed for working on IBLRIG's code-base, run: + +.. code-block:: console + + pdm sync -d + + +Running Unit Tests +^^^^^^^^^^^^^^^^^^ + +To run unit tests locally, run: + +.. code-block:: console + + pdm run pytest + +This will also generate a HTML based coverage report which can be found in the ``htmlcov`` directory. + + +Linting & Formatting +^^^^^^^^^^^^^^^^^^^^ + +We use `Ruff `_ for linting and formatting our code-base in close accordance with `the Black code +style `_. + +To lint your code, run: + +.. code-block:: console + + pdm run ruff check + +Appending the flag ``--fix`` to the above command will automatically fix issues that are deemed safe to handle. + +To reformat your code according to the `Black code style `_ run: + +.. code-block:: console + + pdm run ruff format + +Appending the flag ``--check`` to the above command will check your code for formatting issues without applying any changes. +Refer to `Ruff Formater's documentation `_ for further details. + + +pre-commit +---------- + +IBLRIG v8 supports pre-commit hooks. +Install pre-commit according to the `official guide `_ to enable automated code-checks on commits. + + +Release Checklist +----------------- + +1) update CHANGELOG.md including changes from the last tag +2) Pull request to ``iblrigv8dev`` +3) Check CI and eventually wet lab test +4) Pull request to ``iblrigv8`` +5) Merge PR +6) git tag the release in accordance to the version number below (after merge!) + + +Building the documentation +-------------------------- + +To build the documentation, run: + +.. code-block:: console + + pdm run sphinx-autobuild ./docs/source ./docs/build + +You can also export the documentation to a PDF file: + +.. code-block:: console + + pdm run make -C docs/ simplepdf + +Find the exported PDF file in ``docs/build/simplepdf``. + + +Contribute to the documentation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To write the documentation: + +* Write the documentation in the ``iblrig/docs/source`` folder +* If you are writing in a new file, add it to the ``index.rst`` so it appears in the table of content +* Push all your changes to the ``iblrigv8dev`` branch; if this branch does not exist, create it first + +To release the documentation onto the `website `_: + +* Wait for the next release, or +* Manually trigger the GitHub action by clicking "Run Workflow" (select ``master``) `here `_ diff --git a/_sources/reference_task_qc.rst.txt b/_sources/reference_task_qc.rst.txt new file mode 100644 index 000000000..ef90d8084 --- /dev/null +++ b/_sources/reference_task_qc.rst.txt @@ -0,0 +1,120 @@ +Quality check the task post-usage +================================= + +Once a session is acquired, you can verify whether the trials data is extracted properly and that the sequence of events matches the expected logic of +the task. + +Metrics definitions +------------------- +All the metrics computed as part of the Task logic integrity QC (Task QC) are implemented in +`ibllib `__. +When run at a behavior rig, they are computed using the Bpod data, without alignment to another DAQ's clock. + +.. tip:: + + The Task QC metrics definitions can be found in this `documentation page `__. + See `this page `__ on how to write QC checks for a custom task protocol. + + +Some are essential, i.e. if they fail you should immediately take action and verify your rig, +and some are not as critical. + +Essential taskQCs: + +* check_audio_pre_trial +* check_correct_trial_event_sequence +* check_error_trial_event_sequence +* check_n_trial_events +* check_response_feedback_delays +* check_reward_volume_set +* check_reward_volumes +* check_stimOn_goCue_delays +* check_stimulus_move_before_goCue +* check_wheel_move_before_feedback +* check_wheel_freeze_during_quiescence + +Non essential taskQCs: + +* check_stimOff_itiIn_delays +* check_positive_feedback_stimOff_delays +* check_negative_feedback_stimOff_delays +* check_wheel_move_during_closed_loop +* check_response_stimFreeze_delays +* check_detected_wheel_moves +* check_trial_length +* check_goCue_delays +* check_errorCue_delays +* check_stimOn_delays +* check_stimOff_delays +* check_iti_delays +* check_stimFreeze_delays +* check_wheel_integrity + +.. tip:: + + The value returned by each metric is the proportion of trial that fail to pass the given test. + For example, if the value returned by ``check_errorCue_delays`` is 0.92, it means 8% of the trials failed this test. + +Quantifying the task QC outcome at the session level +---------------------------------------------------- + +The criteria for whether a session passes the Task QC is: + +* ``NOT_SET``: default value (= not run yet) +* ``FAIL``: if at least one metric is < 95% +* ``WARNING``: if all metrics are >=95% , and at least one metric is <99 % +* ``PASS``: if all metrics are >= 99% + +This aggregation is done on all metrics, regardless if they are essential or not. + +The criteria is defined at +`this code line `__ + +How to check the task QC outcome +-------------------------------- + +Immediately after acquiring a session +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +At the behaviour PC, before the data have been copied, use the `task_qc` command with the session path: + +.. code-block:: shell-session + + task_qc C:\iblrigv8_data\Subjects\KS022\2019-12-10\001 --local + +More information can be found `here `__, or by running `task_qc --help`. + +Once the session is registered on Alyx +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. **Check on the Alyx webpage** + + From the `session overview page on Alyx `__, + find your session click on ``See more session info``. + The session QC is displayed in one of the right panels. + + To get more information regarding which test pass or fail (contributing to this overall session QC), + you can click on the ``QC`` menu on the left. Bar-diagrams will appear, with essentials QCs on the + left, colored in green if passing. + + .. tip:: + You can hover over the bars with your mouse to easily know the name of the corresponding metric. + This is useful if the value of the metric is ``0``. + + .. warning:: + If an :ref:`essential metric` fails, run the Task QC Viewer to investigate why. + +2. **Run the taskQC Viewer to investigate** + + The application `Task QC Viewer `__ + enables to visualise the data streams of problematic trials. + + .. tip:: + Unlike when run at the behaviour PC, after registration the QC is run on the final time-aligned data (if applicable). + + + .. exercise:: Run the task QC metrics and viewer + + Select the ``eid`` for your session to inspect, and run the following within the iblrig env: + + .. code-block:: shell-session + + task_qc baecbddc-2b86-4eaf-a6f2-b30923225609 diff --git a/_sources/reference_write_your_own_task.rst.txt b/_sources/reference_write_your_own_task.rst.txt new file mode 100644 index 000000000..b61a2a8ea --- /dev/null +++ b/_sources/reference_write_your_own_task.rst.txt @@ -0,0 +1,130 @@ +Guide to develop a custom task +============================== + +iblrigv8 design: inheritance +---------------------------- + +During the lifetime of the IBL project, we realized that multiple task variants combine with multiple hardware configurations and acquisition modalities, leading to a combinatorial explosion of possible tasks and related hardware. + +This left us with the only option of developing a flexible task framework through hierarchical inheritance. + +All tasks inherit from the :class:`iblrig.base_tasks.BaseSession` class, which provides the following functionalities: + - read hardware parameters and rig parameters + - optionally interfaces with the `Alyx experimental database `_ + - creates the folder structure for the session + - writes the task and rig parameters, log, and :doc:`acquisition description files <../reference_description_file>` + +Additionally the :mod:`iblrig.base_tasks` module provides "hardware mixins". Those are classes that provide hardware-specific functionalities, such as connecting to a Bpod or a rotary encoder. They are composed with the :class:`~.iblrig.base_tasks.BaseSession` class to create a task. + +.. warning:: + + This sounds complicated ? It is ! + Forecasting all possible tasks and hardware add-ons and modification is fool's errand, however we can go through specific examples of task implementations. + + +Guide to Creating Your Own Task +------------------------------- + +What Happens When Running an IBL Task? + +1. The task constructor is invoked, executing the following steps: + + - Reading of settings: hardware and IBLRIG configurations. + - Reading of task parameters. + - Instantiation of hardware mixins. + +2. The task initiates the :meth:`~.iblrig.base_tasks.run` method. Prior to execution, this + method: + + - Launches the hardware modules. + - Establishes a session folder. + - Saves the parameters to disk. + +3. The experiment unfolds: the :meth:`~.iblrig.base_tasks.run` method triggers the ``_run()`` + method within the child class: + + - Typically, this involves a loop that generates a Bpod state + machine for each trial and runs it. + +4. Upon SIGINT or when the maximum trial count is reached, the + experiment concludes. The end of the :meth:`~.iblrig.base_tasks.run` method includes: + + - Saving the final parameter file. + - Recording administered water and session performance on Alyx. + - Halting the mixins. + - Initiating local server transfer. + +Examples +-------- + +.. admonition:: Where to write your task + :class: seealso + + After the :doc:`installation of iblrig <../installation>` the `project extraction `_ repository is located at the root of the C: drive. + New tasks should be added to the ``C:\project_extraction\iblrig_custom_tasks`` folder to be made visible by the `iblrig` GUI. + We use a convention that the task name starts with the author identifier, followed by an underscore, followed by the task name, such as `olivier_awesomeChoiceWorld`. + + + olivier_awesomeChoiceWorld + - __init__.py + - task.py + - README.md + - task_parameters.yaml + - test_olivier_awesomeChoiceWorld.py + + +Example 1: variation on biased choice world +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We will create a a choice world task that modifies a the quiescence period duration random draw policy. +In the `task.py` file, the first step is to create a new task class that inherits from the ``BiasedChoiceWorldSession`` class. + +Then we want to make sure that the task bears a distinctive protocol name, `_iblrig_tasks_imagingChoiceWorld`. +We also create the command line entry point for the task that will be used by the `iblrig` GUI. + +Also, in this case we can leverage the IBL infrastructure to perform extraction of the trials using existing extractors `extractor_tasks = ['TrialRegisterRaw', 'ChoiceWorldTrials']` + + .. code-block:: python + + import iblrig.misc + from iblrig.base_choice_world import BiasedChoiceWorldSession + + + class Session(BiasedChoiceWorldSession): + protocol_name = "_iblrig_tasks_imagingChoiceWorld" + + def __init__(self, *args, **kwargs): + self.extractor_tasks = ['TrialRegisterRaw', 'ChoiceWorldTrials'] + super().__init__(*args, **kwargs) + + if __name__ == "__main__": # pragma: no cover + kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()]) + sess = Session(**kwargs) + sess.run() + + +In this case the parent class `BiasedChoiceWorldSession` has a method that draws the quiescence period. We are going to overload this method to add our own policy. This means the parent method will be fully replaced by our implementation. +The class now looks like this: + + .. code-block:: python + + class Session(BiasedChoiceWorldSession): + protocol_name = "_iblrig_tasks_imagingChoiceWorld" + + def draw_quiescent_period(self): + """ + For this task we double the quiescence period texp draw and remove the absolute + offset of 200ms. The resulting is a truncated exp distribution between 400ms and 1 sec + """ + return iblrig.misc.texp(factor=0.35 * 2, min_=0.2 * 2, max_=0.5 * 2) + +Et voilà, in a few lines, we re-used the whole biased choice world implementation to add a custom parameter. This is the most trivial and easy example. +The full code is available `here `_. + + +Example 2: re-writing a state-machine for a biased choice world task +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some instances changes in the task logic require to go deeper and re-write the sequence of task events. In bpod parlance, we are talking about rewritng the state-machine code. + +Coming, for now here is an example of such a `task `_. diff --git a/_sources/usage.rst.txt b/_sources/usage.rst.txt new file mode 100644 index 000000000..344039fef --- /dev/null +++ b/_sources/usage.rst.txt @@ -0,0 +1,8 @@ +************************************ +Using IBLRIG v8 +************************************ + +.. include:: usage_behavior.rst +.. include:: usage_copy.rst +.. include:: usage_video.rst +.. include:: usage_neuropixel.rst diff --git a/_sources/usage_behavior.rst.txt b/_sources/usage_behavior.rst.txt new file mode 100644 index 000000000..23d96f84d --- /dev/null +++ b/_sources/usage_behavior.rst.txt @@ -0,0 +1,110 @@ +Running a behaviour experiment +============================== + +IBLRIG v8 provides users with two distinct interfaces: a command line interface (CLI) and a graphical user interface (GUI). +The CLI encompasses the complete functionality of IBLRIG, upon which the GUI is constructed to enhance user-friendliness. +All tasks achievable through the GUI are equally achievable through the CLI. + + +The Graphical User Interface +---------------------------- + +To initiate a task through the graphical user interface, open a Windows PowerShell and enter: + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + iblrig + +These commands activate the necessary environment and launch the IBLRIG Wizard GUI as shown below: + +.. figure:: img/gui.png + :alt: A screenshot of IBL Rig Wizard + :align: center + + A screenshot of IBLRIG Wizard + + +Starting a Task +~~~~~~~~~~~~~~~ + +1. Enter your Alyx username, then click on the *Connect* button. This + action will automatically populate the GUI fields with information + pertinent to your lab. + +2. Select the desired values from the provided options. Utilize the + *Filter* field to swiftly narrow down the list of displayed subjects. + Note that selections for *Project* and *Procedure* are mandatory. + +3. Click the *Start* button to initiate the task. + + +Supplementary Controls +~~~~~~~~~~~~~~~~~~~~~~ + +- When starting a subsequent task with the same subject, you'll be asked if + you want to append to the preceding session. Doing so will result in a + sequence of connected tasks sharing the same data folder. + +- The *Flush* button serves to toggle the valve for cleaning purposes. + +.. note:: + IBLRIG's Graphical User Interface is still work-in-progress. If you have any suggestions to make the GUI + more usable, please add an `issue on GitHub `_ or approach the dev-team on Slack! + We are happy to discuss possible changes with you! + + +Interfacing with Alyx +--------------------- + +Although this is not mandatory, the IBLRIG GUI is designed to interface with `Alyx `_, the International Brain Laboratory's database. +This feature allows users to access their subjects and projects directly from the GUI, without the need to manually enter this information. + +To enable this feature, you must have an Alyx account and have configured your database URL and credentials as mentioned :doc:`installation`. + +- The *subjects* available are the set of alyx subjects that are alive, not stock, and belong to the lab defined in the `iblrig_settings.py` file. +- The *projects* available are the set of projects of which the current user is a participant. Login to Alyx > Subjects > Projects to check your projects. + + +The Command Line Interface +-------------------------- + +To use the command line interface, open a terminal and activate the +environment: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + +Running a single task +~~~~~~~~~~~~~~~~~~~~~ + +To run a single task, execute the following command: + +.. code:: powershell + + python .\iblrig_tasks\_iblrig_tasks_trainingChoiceWorld\task.py --subject algernon --user john.doe + +Chaining several tasks together +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To chain several tasks together, use the ``--append`` flag. For +instance, to run a passive task after an ephys task: + +1. Run the ephys task + + .. code:: powershell + + .\iblrig_tasks\_iblrig_tasks_ephysChoiceWorld\task.py --subject algernon + +2. Run the passive task with the ``--append``\ flag: + + .. code:: powershell + + .\iblrig_tasks\_iblrig_tasks_passiveChoiceWorld\task.py --subject algernon --append + +Flushing the valve +~~~~~~~~~~~~~~~~~~ + +To flush valve 1 of the Bpod, type ``flush`` and confirm with ENTER. Press ENTER again to close the valve. diff --git a/_sources/usage_copy.rst.txt b/_sources/usage_copy.rst.txt new file mode 100644 index 000000000..66d75ade8 --- /dev/null +++ b/_sources/usage_copy.rst.txt @@ -0,0 +1,177 @@ + +Copy commands +============= + +Usage +----- + +To initiate the data transfer from the local server to the remote +server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag behavior + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. + +To copy data at another acquisition PC, such as video and ephys, use the relevant tag, e.g. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag video + +NB: By default the local data that was copied over 2 weeks ago will be automatically removed. To +avoid this set the cleanup-weeks argument to -1: + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data behavior --cleanup-weeks -1 + +See the 'Clean-up local data' section on how to remove data without calling the copy script. + +To view the copy status of your local sessions without actually copying, use the 'dry' argument: + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data behavior --dry + +For more information on the tranfer_data arguments, use the help flag: + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --help + + +Clean-up local data +------------------- + +To remove sessions fully copied to the server and older than 2 weeks, +open a terminal and type: + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + remove-old-sessions + +Note: the server needs to be up and running or the sessions won’t be +verified as copied. + + +Behind the Copy Scripts +----------------------- + +Workflow +~~~~~~~~ + +1. **Initial Stub Creation:** At the start of acquisition, an incomplete + experiment description file - a *‘stub’* - is saved to the session + on, both, the local PC and the lab server in a subfolder called + ``_devices``. The filename of the stub includes the PC’s identifier, + allowing the copy script to identify its source. + +2. **Executing the Copy Script:** The copy script is executed on each + acquisition PC independently and in no particular order. + +3. **Navigating Local Session Data:** The script systematically + navigates through local session folders (or optionally a separate + ``transfers`` folder) that contain ``experiment.description`` stubs. + +4. **Skipping Transferred Sessions:** The script ignores session folders + containing a file named ``transferred.flag`` (see 7). + +5. **Copying Collections:** For each session, the script reads the + respective stub and uses ``rsync`` to copy each ``collection``. + Subfolders not specified under a ``collection`` key are omitted from + copying. + +6. **Removing Remote Stubs:** Upon successful copying, the remote stub + file is merged with the remote ``experiment.description`` file (or + copied over if one doesn’t exist already). The remote stub file is + then deleted. + +7. **Confirming Transfer Locally:** A ``transferred.flag`` file is + created in the local session folder to confirm the transfer’s + success. + +8. **Completion and Cleanup:** Once no more remote stub files exist + for a given session, the empty ``_devices`` subfolder is removed. + Additionally, a ‘raw_session.flag’ file is created in the remote session folder, + indicating the successful transfer of all files. + +Example of workflow +~~~~~~~~~~~~~~~~~~~ + +Example of three sessions each in a different copy state: + +* The State on the Remote Lab Server + :: + + lab server/ + └── subject/ + └── 2020-01-01/ + ├── 001/ + │ └── _devices/ + │ ├── 2020-01-01_1_subject@taskPC.yaml + │ └── 2020-01-01_1_subject@ephysPC.yaml + ├── 002/ + │ ├── _ibl_experiment.description.yaml + │ ├── raw_task_data_00/ + │ └── _devices/ + │ └── 2020-01-01_1_subject@ephysPC.yaml + └── 003/ + ├── raw_task_data_00/ + ├── raw_ephys_data/ + ├── _ibl_experiment.description.yaml + └── raw_session.flag + + +* The State on the Local Task Acquisition PC + :: + + acquisition computer (taskPC)/ + └── subject/ + └── 2020-01-01/ + ├── 001/ + │ ├── raw_task_data_00/ + │ └── _ibl_experiment.description_taskPC.yaml + ├── 002/ + │ ├── raw_task_data_00/ + │ ├── _ibl_experiment.description_taskPC.yaml + │ └── transferred.flag + └── 003/ + ├── raw_task_data_00/ + ├── folder_not_in_desc_file/ + ├── _ibl_experiment.description_taskPC.yaml + └── transferred.flag + + +* The State on the Local Ephys Acquisition PC + :: + + acquisition computer (ephysPC)/ + └── subject/ + └── 2020-01-01/ + ├── 001/ + │ ├── raw_ephys_data/ + │ └── _ibl_experiment.description_ephysPC.yaml + ├── 002/ + │ ├── raw_ephys_data/ + │ ├── _ibl_experiment.description_ephysPC.yaml + └── 003/ + ├── raw_ephys_data/ + ├── folder_not_in_desc_file/ + ├── _ibl_experiment.description_ephysPC.yaml + └── transferred.flag + +With the lab server and acquisition pcs in the states above, the +sessions are in the following states + +* ``subject/2020-01-01/001`` no data have been copied. +* ``subject/2020-01-01/002`` data from *taskPC* have been copied, data from *ephysPC* remains to be copied. +* ``subject/2020-01-01/003`` data copied from all acquisition PCs. diff --git a/_sources/usage_neuropixel.rst.txt b/_sources/usage_neuropixel.rst.txt new file mode 100644 index 000000000..f315d3c84 --- /dev/null +++ b/_sources/usage_neuropixel.rst.txt @@ -0,0 +1,66 @@ +Neuropixel recording with iblrigv8 +================================== + +This document describes how to use the iblrigv8 software to record from the Neuropixel computer. + +Setup +----- + +Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer. + +To get access to the viewephys visualizer: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + pip install viewephys + +Starting a task +--------------- + +Below shows how to start the electrophysiology for the subject 'example' with 2 probes: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_ephys_session example 2 + + +Copy command +------------ + +Usage +~~~~~ + +To initiate the data transfer from the local server to the remote server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag ephys + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. + + +Look at the raw data +-------------------- + +This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display. + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + viewephys + +.. image:: img/viewephys.png + :width: 800 + :alt: Alternative text + + +More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys \ No newline at end of file diff --git a/_sources/usage_video.rst.txt b/_sources/usage_video.rst.txt new file mode 100644 index 000000000..c5160e286 --- /dev/null +++ b/_sources/usage_video.rst.txt @@ -0,0 +1,81 @@ +Video acquisition computer +========================== + +Video can be run on a separate computer, which is recommended when recording multiple cameras. + + +Setup +----- + +Installing drivers +~~~~~~~~~~~~~~~~~~ + +Both spinnaker and pyspin must be installed before running an experiment: + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + install_spinnaker + install_pyspin + + +Settings config +~~~~~~~~~~~~~~~ + +The camera acquisition is configured by parameters in the 'device_cameras' key of the `hardware_settings.yaml` file. +Below is an overview of the parameters: + +.. code:: yaml + + device_cameras: + # The name of the configuration. This is passed to the CLI. + default: + # This is required: the Bonsai workflows to be called by the CLI script. + BONSAI_WORKFLOW: + # Optional setup (e.g. alignment) workflow + setup: devices/camera_setup/EphysRig_SetupCameras.bonsai + # Required workflow to be called when the experiment starts + recording: devices/camera_recordings/TrainingRig_SaveVideo_TrainingTasks.bonsai + # Camera #1 name + left: + # Required camera device index (assigned in driver software) + INDEX: 1 + # Optional expected frame height. Actual resolution should be set in the driver software. + HEIGHT: 1024 + # Optional expected frame width. This is simply used in QC. + WIDTH: 1280 + # Optional expected frame rate (Hz). This is simply used in QC. + FPS: 30 + +Multiple configurations can be added, e.g. 'default', 'training', 'ephys', etc. and within each, multiple cameras +can be added, e.g. 'left', 'right', 'body', etc. Each configuration requires a `BONSAI_WORKFLOW: recording` key; +each camera requires an `INDEX` key. + + +Starting a task +--------------- + +Below shows how to start the cameras for the subject 'example' with configuration 'default': + +.. code:: powershell + + cd C:\iblrigv8\ + venv\scripts\Activate.ps1 + start_video_session example default + +Copy command +------------ + +Usage +~~~~~ + +To initiate the data transfer from the local server to the remote server, open a terminal and type. + +.. code:: powershell + + C:\iblrigv8\venv\scripts\Activate.ps1 + transfer_data --tag video + +The transfer local and remote directories are set in the +``iblrig/settings/iblrig_settings.py`` file. diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 000000000..81415803e --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 000000000..f316efcb4 --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 000000000..92fad4b5c --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 000000000..54b3c4638 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 000000000..f1916ec7d --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 000000000..2ea7ff3e2 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 000000000..dbe1aaad7 --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 000000000..c718cee44 --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 000000000..6cb600001 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 000000000..7059e2314 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 000000000..f815f63f9 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 000000000..f2c76e5bd Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 000000000..e9f60ca95 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 000000000..855c845e5 --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 000000000..35acda2fa Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 000000000..400014a4b Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 000000000..4d13fc604 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 000000000..88ad05b9f Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 000000000..c4e3d804b Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 000000000..c6dff51f0 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 000000000..bb195043c Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 000000000..76114bc03 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 000000000..3404f37e2 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 000000000..ae1307ff5 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 000000000..3bf984332 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 000000000..19a446a0e --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 000000000..4d67807d1 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 000000000..0ddbcc814 --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '8.24.1', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 000000000..a858a410e Binary files /dev/null and b/_static/file.png differ diff --git a/_static/graphviz.css b/_static/graphviz.css new file mode 100644 index 000000000..027576e34 --- /dev/null +++ b/_static/graphviz.css @@ -0,0 +1,19 @@ +/* + * graphviz.css + * ~~~~~~~~~~~~ + * + * Sphinx stylesheet -- graphviz extension. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +img.graphviz { + border: 0; + max-width: 100%; +} + +object.graphviz { + max-width: 100%; +} diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 000000000..c4c6022f2 --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 000000000..cd1c674f5 --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 000000000..1fddb6ee4 --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minipres.js b/_static/minipres.js new file mode 100644 index 000000000..ad11c8713 --- /dev/null +++ b/_static/minipres.js @@ -0,0 +1,223 @@ +// Add goTo method to elements +// http://stackoverflow.com/questions/4801655/how-to-go-to-a-specific-element-on-page +(function($) { + $.fn.goTo = function() { + $('html, body').animate({ + scrollTop: $(this).offset().top //+ 'px' + }, 'fast'); + return this; // for chaining... + } +})(jQuery); + +// NO good way to do this!. Copy a hack from here +// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript +// https://stackoverflow.com/a/2880929 +var urlParams; +(window.onpopstate = function () { + var match, + pl = /\+/g, // Regex for replacing addition symbol with a space + search = /([^&=]+)=?([^&]*)/g, + decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); }, + query = window.location.search.substring(1); + urlParams = {}; + while (match = search.exec(query)) + urlParams[decode(match[1])] = decode(match[2]); +})(); + +// Select heading levels +var maxHeading = urlParams['h'] +if (maxHeading === undefined) maxHeading = 2 +var headingLevels = []; +for (h=2 ; h (sections.length-1) ) { + // if we would scroll past bottom, or above top, do nothing + return; + } + + console.log('xxxxxx'); + var targetSection = sections[targetPos]; + console.log(targetSection, typeof(targetSection)); + + // Return targetSection top and height + var secProperties = section_top_and_height(targetSection); + var top = secProperties['top']; + var height = secProperties['height'] + var win_height = window.innerHeight; + //console.info(top, height, win_height) + + var scroll_to = 0; + if (height >= win_height || height == 0) { + scroll_to = top; + } else { + scroll_to = top - (win_height-height)/3.; + } + //console.info(top, height, win_height, scroll_to) + + $('html, body').animate({ + scrollTop: scroll_to //+ 'px' + }, 'fast'); + +} + + +function minipres() { + /* Enable the minipres mode: + - call the hide() function + - set up the scrolling listener + */ + document.addEventListener('keydown', function (event) { + switch(event.which) { + case 37: // left + switch_slide(-1); + event.preventDefault(); + return false; + break; + //case 38: // up + case 39: // right + switch_slide(+1); + event.preventDefault(); + return false; + break; + //case 40: // down + default: + return; // exit this handler for other keys + } + }, true) + + hide() + + // Increase space between sections + //$("div .section").css('margin-bottom', '50%'); + $(sectionSelector).css('margin-top', '50%'); + + // Reduce size/color of other sections + if (hiddenSectionSelector.length > 0) { + var hideNodes = $(hiddenSectionSelector); + console.log(typeof hideNodes, hideNodes); + for (node in hideNodes) { + console.log("a", typeof node, node); + node = hideNodes[node]; // what's right way to iterate values? + console.log("b", typeof node, node); + if (node.parentNode && node.parentNode.className == "section") { + node = node.parentNode; + console.log("c", typeof node, node); + //node.css['transform'] = 'scale(.5)'; + //node.css['transform-origin'] = 'top center'; + $(node).css('color', 'lightgrey'); + //$(node).css('font-size', '20%'); + //$(node).css('visibility', 'collapse'); + //ntahousnatouhasno; + } + } + } +} + +function hide() { + /* Hide all non-essential elements on the page + */ + + // This is for sphinx_rst_theme and readthedocs + $(".wy-nav-side").remove(); + $(".wy-nav-content-wrap").css('margin-left', 0); + $('.rst-versions').remove(); // readthedocs version selector + + // Add other formats here. +} + + +var slideshow = minipres; + +if (window.location.search.match(/[?&](minipres|slideshow|pres)([=&]|$)/) ) { + //minipres() + window.addEventListener("load", minipres); +} else if (window.location.search.match(/[?&](plain)([=&]|$)/) ) { + window.addEventListener("load", hide); +} diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 000000000..d96755fda Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css b/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css new file mode 100644 index 000000000..335663106 --- /dev/null +++ b/_static/mystnb.4510f1fc1dee50b3e5859aac5469c37c29e427902b24a333a5f9fcb2f0b3ac41.css @@ -0,0 +1,2342 @@ +/* Variables */ +:root { + --mystnb-source-bg-color: #f7f7f7; + --mystnb-stdout-bg-color: #fcfcfc; + --mystnb-stderr-bg-color: #fdd; + --mystnb-traceback-bg-color: #fcfcfc; + --mystnb-source-border-color: #ccc; + --mystnb-source-margin-color: green; + --mystnb-stdout-border-color: #f7f7f7; + --mystnb-stderr-border-color: #f7f7f7; + --mystnb-traceback-border-color: #ffd6d6; + --mystnb-hide-prompt-opacity: 70%; + --mystnb-source-border-radius: .4em; + --mystnb-source-border-width: 1px; +} + +/* Whole cell */ +div.container.cell { + padding-left: 0; + margin-bottom: 1em; +} + +/* Removing all background formatting so we can control at the div level */ +.cell_input div.highlight, +.cell_output pre, +.cell_input pre, +.cell_output .output { + border: none; + box-shadow: none; +} + +.cell_output .output pre, +.cell_input pre { + margin: 0px; +} + +/* Input cells */ +div.cell div.cell_input, +div.cell details.above-input>summary { + padding-left: 0em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + background-color: var(--mystnb-source-bg-color); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; + border-radius: var(--mystnb-source-border-radius); +} + +div.cell_input>div, +div.cell_output div.output>div.highlight { + margin: 0em !important; + border: none !important; +} + +/* All cell outputs */ +.cell_output { + padding-left: 1em; + padding-right: 0em; + margin-top: 1em; +} + +/* Text outputs from cells */ +.cell_output .output.text_plain, +.cell_output .output.traceback, +.cell_output .output.stream, +.cell_output .output.stderr { + margin-top: 1em; + margin-bottom: 0em; + box-shadow: none; +} + +.cell_output .output.text_plain, +.cell_output .output.stream { + background: var(--mystnb-stdout-bg-color); + border: 1px solid var(--mystnb-stdout-border-color); +} + +.cell_output .output.stderr { + background: var(--mystnb-stderr-bg-color); + border: 1px solid var(--mystnb-stderr-border-color); +} + +.cell_output .output.traceback { + background: var(--mystnb-traceback-bg-color); + border: 1px solid var(--mystnb-traceback-border-color); +} + +/* Collapsible cell content */ +div.cell details.above-input div.cell_input { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-top: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; +} + +div.cell div.cell_input.above-output-prompt { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.cell details.above-input>summary { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: var(--mystnb-source-border-width) var(--mystnb-source-border-color) dashed; + padding-left: 1em; + margin-bottom: 0; +} + +div.cell details.above-output>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.below-input>summary { + background-color: var(--mystnb-source-bg-color); + padding-left: 1em; + padding-right: 0em; + border: var(--mystnb-source-border-width) var(--mystnb-source-border-color) solid; + border-top: none; + border-bottom-left-radius: var(--mystnb-source-border-radius); + border-bottom-right-radius: var(--mystnb-source-border-radius); + border-left-color: var(--mystnb-source-margin-color); + border-left-width: medium; +} + +div.cell details.hide>summary>span { + opacity: var(--mystnb-hide-prompt-opacity); +} + +div.cell details.hide[open]>summary>span.collapsed { + display: none; +} + +div.cell details.hide:not([open])>summary>span.expanded { + display: none; +} + +@keyframes collapsed-fade-in { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} +div.cell details.hide[open]>summary~* { + -moz-animation: collapsed-fade-in 0.3s ease-in-out; + -webkit-animation: collapsed-fade-in 0.3s ease-in-out; + animation: collapsed-fade-in 0.3s ease-in-out; +} + +/* Math align to the left */ +.cell_output .MathJax_Display { + text-align: left !important; +} + +/* Pandas tables. Pulled from the Jupyter / nbsphinx CSS */ +div.cell_output table { + border: none; + border-collapse: collapse; + border-spacing: 0; + color: black; + font-size: 1em; + table-layout: fixed; +} + +div.cell_output thead { + border-bottom: 1px solid black; + vertical-align: bottom; +} + +div.cell_output tr, +div.cell_output th, +div.cell_output td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +div.cell_output th { + font-weight: bold; +} + +div.cell_output tbody tr:nth-child(odd) { + background: #f5f5f5; +} + +div.cell_output tbody tr:hover { + background: rgba(66, 165, 245, 0.2); +} + +/** source code line numbers **/ +span.linenos { + opacity: 0.5; +} + +/* Inline text from `paste` operation */ + +span.pasted-text { + font-weight: bold; +} + +span.pasted-inline img { + max-height: 2em; +} + +tbody span.pasted-inline img { + max-height: none; +} + +/* Font colors for translated ANSI escape sequences +Color values are copied from Jupyter Notebook +https://github.com/jupyter/notebook/blob/52581f8eda9b319eb0390ac77fe5903c38f81e3e/notebook/static/notebook/less/ansicolors.less#L14-L21 +Background colors from +https://nbsphinx.readthedocs.io/en/latest/code-cells.html#ANSI-Colors +*/ +div.highlight .-Color-Bold { + font-weight: bold; +} + +div.highlight .-Color[class*=-Black] { + color: #3E424D +} + +div.highlight .-Color[class*=-Red] { + color: #E75C58 +} + +div.highlight .-Color[class*=-Green] { + color: #00A250 +} + +div.highlight .-Color[class*=-Yellow] { + color: #DDB62B +} + +div.highlight .-Color[class*=-Blue] { + color: #208FFB +} + +div.highlight .-Color[class*=-Magenta] { + color: #D160C4 +} + +div.highlight .-Color[class*=-Cyan] { + color: #60C6C8 +} + +div.highlight .-Color[class*=-White] { + color: #C5C1B4 +} + +div.highlight .-Color[class*=-BGBlack] { + background-color: #3E424D +} + +div.highlight .-Color[class*=-BGRed] { + background-color: #E75C58 +} + +div.highlight .-Color[class*=-BGGreen] { + background-color: #00A250 +} + +div.highlight .-Color[class*=-BGYellow] { + background-color: #DDB62B +} + +div.highlight .-Color[class*=-BGBlue] { + background-color: #208FFB +} + +div.highlight .-Color[class*=-BGMagenta] { + background-color: #D160C4 +} + +div.highlight .-Color[class*=-BGCyan] { + background-color: #60C6C8 +} + +div.highlight .-Color[class*=-BGWhite] { + background-color: #C5C1B4 +} + +/* Font colors for 8-bit ANSI */ + +div.highlight .-Color[class*=-C0] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC0] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C1] { + color: #800000 +} + +div.highlight .-Color[class*=-BGC1] { + background-color: #800000 +} + +div.highlight .-Color[class*=-C2] { + color: #008000 +} + +div.highlight .-Color[class*=-BGC2] { + background-color: #008000 +} + +div.highlight .-Color[class*=-C3] { + color: #808000 +} + +div.highlight .-Color[class*=-BGC3] { + background-color: #808000 +} + +div.highlight .-Color[class*=-C4] { + color: #000080 +} + +div.highlight .-Color[class*=-BGC4] { + background-color: #000080 +} + +div.highlight .-Color[class*=-C5] { + color: #800080 +} + +div.highlight .-Color[class*=-BGC5] { + background-color: #800080 +} + +div.highlight .-Color[class*=-C6] { + color: #008080 +} + +div.highlight .-Color[class*=-BGC6] { + background-color: #008080 +} + +div.highlight .-Color[class*=-C7] { + color: #C0C0C0 +} + +div.highlight .-Color[class*=-BGC7] { + background-color: #C0C0C0 +} + +div.highlight .-Color[class*=-C8] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC8] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C9] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC9] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C10] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC10] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C11] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC11] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C12] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC12] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C13] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC13] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C14] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC14] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C15] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC15] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C16] { + color: #000000 +} + +div.highlight .-Color[class*=-BGC16] { + background-color: #000000 +} + +div.highlight .-Color[class*=-C17] { + color: #00005F +} + +div.highlight .-Color[class*=-BGC17] { + background-color: #00005F +} + +div.highlight .-Color[class*=-C18] { + color: #000087 +} + +div.highlight .-Color[class*=-BGC18] { + background-color: #000087 +} + +div.highlight .-Color[class*=-C19] { + color: #0000AF +} + +div.highlight .-Color[class*=-BGC19] { + background-color: #0000AF +} + +div.highlight .-Color[class*=-C20] { + color: #0000D7 +} + +div.highlight .-Color[class*=-BGC20] { + background-color: #0000D7 +} + +div.highlight .-Color[class*=-C21] { + color: #0000FF +} + +div.highlight .-Color[class*=-BGC21] { + background-color: #0000FF +} + +div.highlight .-Color[class*=-C22] { + color: #005F00 +} + +div.highlight .-Color[class*=-BGC22] { + background-color: #005F00 +} + +div.highlight .-Color[class*=-C23] { + color: #005F5F +} + +div.highlight .-Color[class*=-BGC23] { + background-color: #005F5F +} + +div.highlight .-Color[class*=-C24] { + color: #005F87 +} + +div.highlight .-Color[class*=-BGC24] { + background-color: #005F87 +} + +div.highlight .-Color[class*=-C25] { + color: #005FAF +} + +div.highlight .-Color[class*=-BGC25] { + background-color: #005FAF +} + +div.highlight .-Color[class*=-C26] { + color: #005FD7 +} + +div.highlight .-Color[class*=-BGC26] { + background-color: #005FD7 +} + +div.highlight .-Color[class*=-C27] { + color: #005FFF +} + +div.highlight .-Color[class*=-BGC27] { + background-color: #005FFF +} + +div.highlight .-Color[class*=-C28] { + color: #008700 +} + +div.highlight .-Color[class*=-BGC28] { + background-color: #008700 +} + +div.highlight .-Color[class*=-C29] { + color: #00875F +} + +div.highlight .-Color[class*=-BGC29] { + background-color: #00875F +} + +div.highlight .-Color[class*=-C30] { + color: #008787 +} + +div.highlight .-Color[class*=-BGC30] { + background-color: #008787 +} + +div.highlight .-Color[class*=-C31] { + color: #0087AF +} + +div.highlight .-Color[class*=-BGC31] { + background-color: #0087AF +} + +div.highlight .-Color[class*=-C32] { + color: #0087D7 +} + +div.highlight .-Color[class*=-BGC32] { + background-color: #0087D7 +} + +div.highlight .-Color[class*=-C33] { + color: #0087FF +} + +div.highlight .-Color[class*=-BGC33] { + background-color: #0087FF +} + +div.highlight .-Color[class*=-C34] { + color: #00AF00 +} + +div.highlight .-Color[class*=-BGC34] { + background-color: #00AF00 +} + +div.highlight .-Color[class*=-C35] { + color: #00AF5F +} + +div.highlight .-Color[class*=-BGC35] { + background-color: #00AF5F +} + +div.highlight .-Color[class*=-C36] { + color: #00AF87 +} + +div.highlight .-Color[class*=-BGC36] { + background-color: #00AF87 +} + +div.highlight .-Color[class*=-C37] { + color: #00AFAF +} + +div.highlight .-Color[class*=-BGC37] { + background-color: #00AFAF +} + +div.highlight .-Color[class*=-C38] { + color: #00AFD7 +} + +div.highlight .-Color[class*=-BGC38] { + background-color: #00AFD7 +} + +div.highlight .-Color[class*=-C39] { + color: #00AFFF +} + +div.highlight .-Color[class*=-BGC39] { + background-color: #00AFFF +} + +div.highlight .-Color[class*=-C40] { + color: #00D700 +} + +div.highlight .-Color[class*=-BGC40] { + background-color: #00D700 +} + +div.highlight .-Color[class*=-C41] { + color: #00D75F +} + +div.highlight .-Color[class*=-BGC41] { + background-color: #00D75F +} + +div.highlight .-Color[class*=-C42] { + color: #00D787 +} + +div.highlight .-Color[class*=-BGC42] { + background-color: #00D787 +} + +div.highlight .-Color[class*=-C43] { + color: #00D7AF +} + +div.highlight .-Color[class*=-BGC43] { + background-color: #00D7AF +} + +div.highlight .-Color[class*=-C44] { + color: #00D7D7 +} + +div.highlight .-Color[class*=-BGC44] { + background-color: #00D7D7 +} + +div.highlight .-Color[class*=-C45] { + color: #00D7FF +} + +div.highlight .-Color[class*=-BGC45] { + background-color: #00D7FF +} + +div.highlight .-Color[class*=-C46] { + color: #00FF00 +} + +div.highlight .-Color[class*=-BGC46] { + background-color: #00FF00 +} + +div.highlight .-Color[class*=-C47] { + color: #00FF5F +} + +div.highlight .-Color[class*=-BGC47] { + background-color: #00FF5F +} + +div.highlight .-Color[class*=-C48] { + color: #00FF87 +} + +div.highlight .-Color[class*=-BGC48] { + background-color: #00FF87 +} + +div.highlight .-Color[class*=-C49] { + color: #00FFAF +} + +div.highlight .-Color[class*=-BGC49] { + background-color: #00FFAF +} + +div.highlight .-Color[class*=-C50] { + color: #00FFD7 +} + +div.highlight .-Color[class*=-BGC50] { + background-color: #00FFD7 +} + +div.highlight .-Color[class*=-C51] { + color: #00FFFF +} + +div.highlight .-Color[class*=-BGC51] { + background-color: #00FFFF +} + +div.highlight .-Color[class*=-C52] { + color: #5F0000 +} + +div.highlight .-Color[class*=-BGC52] { + background-color: #5F0000 +} + +div.highlight .-Color[class*=-C53] { + color: #5F005F +} + +div.highlight .-Color[class*=-BGC53] { + background-color: #5F005F +} + +div.highlight .-Color[class*=-C54] { + color: #5F0087 +} + +div.highlight .-Color[class*=-BGC54] { + background-color: #5F0087 +} + +div.highlight .-Color[class*=-C55] { + color: #5F00AF +} + +div.highlight .-Color[class*=-BGC55] { + background-color: #5F00AF +} + +div.highlight .-Color[class*=-C56] { + color: #5F00D7 +} + +div.highlight .-Color[class*=-BGC56] { + background-color: #5F00D7 +} + +div.highlight .-Color[class*=-C57] { + color: #5F00FF +} + +div.highlight .-Color[class*=-BGC57] { + background-color: #5F00FF +} + +div.highlight .-Color[class*=-C58] { + color: #5F5F00 +} + +div.highlight .-Color[class*=-BGC58] { + background-color: #5F5F00 +} + +div.highlight .-Color[class*=-C59] { + color: #5F5F5F +} + +div.highlight .-Color[class*=-BGC59] { + background-color: #5F5F5F +} + +div.highlight .-Color[class*=-C60] { + color: #5F5F87 +} + +div.highlight .-Color[class*=-BGC60] { + background-color: #5F5F87 +} + +div.highlight .-Color[class*=-C61] { + color: #5F5FAF +} + +div.highlight .-Color[class*=-BGC61] { + background-color: #5F5FAF +} + +div.highlight .-Color[class*=-C62] { + color: #5F5FD7 +} + +div.highlight .-Color[class*=-BGC62] { + background-color: #5F5FD7 +} + +div.highlight .-Color[class*=-C63] { + color: #5F5FFF +} + +div.highlight .-Color[class*=-BGC63] { + background-color: #5F5FFF +} + +div.highlight .-Color[class*=-C64] { + color: #5F8700 +} + +div.highlight .-Color[class*=-BGC64] { + background-color: #5F8700 +} + +div.highlight .-Color[class*=-C65] { + color: #5F875F +} + +div.highlight .-Color[class*=-BGC65] { + background-color: #5F875F +} + +div.highlight .-Color[class*=-C66] { + color: #5F8787 +} + +div.highlight .-Color[class*=-BGC66] { + background-color: #5F8787 +} + +div.highlight .-Color[class*=-C67] { + color: #5F87AF +} + +div.highlight .-Color[class*=-BGC67] { + background-color: #5F87AF +} + +div.highlight .-Color[class*=-C68] { + color: #5F87D7 +} + +div.highlight .-Color[class*=-BGC68] { + background-color: #5F87D7 +} + +div.highlight .-Color[class*=-C69] { + color: #5F87FF +} + +div.highlight .-Color[class*=-BGC69] { + background-color: #5F87FF +} + +div.highlight .-Color[class*=-C70] { + color: #5FAF00 +} + +div.highlight .-Color[class*=-BGC70] { + background-color: #5FAF00 +} + +div.highlight .-Color[class*=-C71] { + color: #5FAF5F +} + +div.highlight .-Color[class*=-BGC71] { + background-color: #5FAF5F +} + +div.highlight .-Color[class*=-C72] { + color: #5FAF87 +} + +div.highlight .-Color[class*=-BGC72] { + background-color: #5FAF87 +} + +div.highlight .-Color[class*=-C73] { + color: #5FAFAF +} + +div.highlight .-Color[class*=-BGC73] { + background-color: #5FAFAF +} + +div.highlight .-Color[class*=-C74] { + color: #5FAFD7 +} + +div.highlight .-Color[class*=-BGC74] { + background-color: #5FAFD7 +} + +div.highlight .-Color[class*=-C75] { + color: #5FAFFF +} + +div.highlight .-Color[class*=-BGC75] { + background-color: #5FAFFF +} + +div.highlight .-Color[class*=-C76] { + color: #5FD700 +} + +div.highlight .-Color[class*=-BGC76] { + background-color: #5FD700 +} + +div.highlight .-Color[class*=-C77] { + color: #5FD75F +} + +div.highlight .-Color[class*=-BGC77] { + background-color: #5FD75F +} + +div.highlight .-Color[class*=-C78] { + color: #5FD787 +} + +div.highlight .-Color[class*=-BGC78] { + background-color: #5FD787 +} + +div.highlight .-Color[class*=-C79] { + color: #5FD7AF +} + +div.highlight .-Color[class*=-BGC79] { + background-color: #5FD7AF +} + +div.highlight .-Color[class*=-C80] { + color: #5FD7D7 +} + +div.highlight .-Color[class*=-BGC80] { + background-color: #5FD7D7 +} + +div.highlight .-Color[class*=-C81] { + color: #5FD7FF +} + +div.highlight .-Color[class*=-BGC81] { + background-color: #5FD7FF +} + +div.highlight .-Color[class*=-C82] { + color: #5FFF00 +} + +div.highlight .-Color[class*=-BGC82] { + background-color: #5FFF00 +} + +div.highlight .-Color[class*=-C83] { + color: #5FFF5F +} + +div.highlight .-Color[class*=-BGC83] { + background-color: #5FFF5F +} + +div.highlight .-Color[class*=-C84] { + color: #5FFF87 +} + +div.highlight .-Color[class*=-BGC84] { + background-color: #5FFF87 +} + +div.highlight .-Color[class*=-C85] { + color: #5FFFAF +} + +div.highlight .-Color[class*=-BGC85] { + background-color: #5FFFAF +} + +div.highlight .-Color[class*=-C86] { + color: #5FFFD7 +} + +div.highlight .-Color[class*=-BGC86] { + background-color: #5FFFD7 +} + +div.highlight .-Color[class*=-C87] { + color: #5FFFFF +} + +div.highlight .-Color[class*=-BGC87] { + background-color: #5FFFFF +} + +div.highlight .-Color[class*=-C88] { + color: #870000 +} + +div.highlight .-Color[class*=-BGC88] { + background-color: #870000 +} + +div.highlight .-Color[class*=-C89] { + color: #87005F +} + +div.highlight .-Color[class*=-BGC89] { + background-color: #87005F +} + +div.highlight .-Color[class*=-C90] { + color: #870087 +} + +div.highlight .-Color[class*=-BGC90] { + background-color: #870087 +} + +div.highlight .-Color[class*=-C91] { + color: #8700AF +} + +div.highlight .-Color[class*=-BGC91] { + background-color: #8700AF +} + +div.highlight .-Color[class*=-C92] { + color: #8700D7 +} + +div.highlight .-Color[class*=-BGC92] { + background-color: #8700D7 +} + +div.highlight .-Color[class*=-C93] { + color: #8700FF +} + +div.highlight .-Color[class*=-BGC93] { + background-color: #8700FF +} + +div.highlight .-Color[class*=-C94] { + color: #875F00 +} + +div.highlight .-Color[class*=-BGC94] { + background-color: #875F00 +} + +div.highlight .-Color[class*=-C95] { + color: #875F5F +} + +div.highlight .-Color[class*=-BGC95] { + background-color: #875F5F +} + +div.highlight .-Color[class*=-C96] { + color: #875F87 +} + +div.highlight .-Color[class*=-BGC96] { + background-color: #875F87 +} + +div.highlight .-Color[class*=-C97] { + color: #875FAF +} + +div.highlight .-Color[class*=-BGC97] { + background-color: #875FAF +} + +div.highlight .-Color[class*=-C98] { + color: #875FD7 +} + +div.highlight .-Color[class*=-BGC98] { + background-color: #875FD7 +} + +div.highlight .-Color[class*=-C99] { + color: #875FFF +} + +div.highlight .-Color[class*=-BGC99] { + background-color: #875FFF +} + +div.highlight .-Color[class*=-C100] { + color: #878700 +} + +div.highlight .-Color[class*=-BGC100] { + background-color: #878700 +} + +div.highlight .-Color[class*=-C101] { + color: #87875F +} + +div.highlight .-Color[class*=-BGC101] { + background-color: #87875F +} + +div.highlight .-Color[class*=-C102] { + color: #878787 +} + +div.highlight .-Color[class*=-BGC102] { + background-color: #878787 +} + +div.highlight .-Color[class*=-C103] { + color: #8787AF +} + +div.highlight .-Color[class*=-BGC103] { + background-color: #8787AF +} + +div.highlight .-Color[class*=-C104] { + color: #8787D7 +} + +div.highlight .-Color[class*=-BGC104] { + background-color: #8787D7 +} + +div.highlight .-Color[class*=-C105] { + color: #8787FF +} + +div.highlight .-Color[class*=-BGC105] { + background-color: #8787FF +} + +div.highlight .-Color[class*=-C106] { + color: #87AF00 +} + +div.highlight .-Color[class*=-BGC106] { + background-color: #87AF00 +} + +div.highlight .-Color[class*=-C107] { + color: #87AF5F +} + +div.highlight .-Color[class*=-BGC107] { + background-color: #87AF5F +} + +div.highlight .-Color[class*=-C108] { + color: #87AF87 +} + +div.highlight .-Color[class*=-BGC108] { + background-color: #87AF87 +} + +div.highlight .-Color[class*=-C109] { + color: #87AFAF +} + +div.highlight .-Color[class*=-BGC109] { + background-color: #87AFAF +} + +div.highlight .-Color[class*=-C110] { + color: #87AFD7 +} + +div.highlight .-Color[class*=-BGC110] { + background-color: #87AFD7 +} + +div.highlight .-Color[class*=-C111] { + color: #87AFFF +} + +div.highlight .-Color[class*=-BGC111] { + background-color: #87AFFF +} + +div.highlight .-Color[class*=-C112] { + color: #87D700 +} + +div.highlight .-Color[class*=-BGC112] { + background-color: #87D700 +} + +div.highlight .-Color[class*=-C113] { + color: #87D75F +} + +div.highlight .-Color[class*=-BGC113] { + background-color: #87D75F +} + +div.highlight .-Color[class*=-C114] { + color: #87D787 +} + +div.highlight .-Color[class*=-BGC114] { + background-color: #87D787 +} + +div.highlight .-Color[class*=-C115] { + color: #87D7AF +} + +div.highlight .-Color[class*=-BGC115] { + background-color: #87D7AF +} + +div.highlight .-Color[class*=-C116] { + color: #87D7D7 +} + +div.highlight .-Color[class*=-BGC116] { + background-color: #87D7D7 +} + +div.highlight .-Color[class*=-C117] { + color: #87D7FF +} + +div.highlight .-Color[class*=-BGC117] { + background-color: #87D7FF +} + +div.highlight .-Color[class*=-C118] { + color: #87FF00 +} + +div.highlight .-Color[class*=-BGC118] { + background-color: #87FF00 +} + +div.highlight .-Color[class*=-C119] { + color: #87FF5F +} + +div.highlight .-Color[class*=-BGC119] { + background-color: #87FF5F +} + +div.highlight .-Color[class*=-C120] { + color: #87FF87 +} + +div.highlight .-Color[class*=-BGC120] { + background-color: #87FF87 +} + +div.highlight .-Color[class*=-C121] { + color: #87FFAF +} + +div.highlight .-Color[class*=-BGC121] { + background-color: #87FFAF +} + +div.highlight .-Color[class*=-C122] { + color: #87FFD7 +} + +div.highlight .-Color[class*=-BGC122] { + background-color: #87FFD7 +} + +div.highlight .-Color[class*=-C123] { + color: #87FFFF +} + +div.highlight .-Color[class*=-BGC123] { + background-color: #87FFFF +} + +div.highlight .-Color[class*=-C124] { + color: #AF0000 +} + +div.highlight .-Color[class*=-BGC124] { + background-color: #AF0000 +} + +div.highlight .-Color[class*=-C125] { + color: #AF005F +} + +div.highlight .-Color[class*=-BGC125] { + background-color: #AF005F +} + +div.highlight .-Color[class*=-C126] { + color: #AF0087 +} + +div.highlight .-Color[class*=-BGC126] { + background-color: #AF0087 +} + +div.highlight .-Color[class*=-C127] { + color: #AF00AF +} + +div.highlight .-Color[class*=-BGC127] { + background-color: #AF00AF +} + +div.highlight .-Color[class*=-C128] { + color: #AF00D7 +} + +div.highlight .-Color[class*=-BGC128] { + background-color: #AF00D7 +} + +div.highlight .-Color[class*=-C129] { + color: #AF00FF +} + +div.highlight .-Color[class*=-BGC129] { + background-color: #AF00FF +} + +div.highlight .-Color[class*=-C130] { + color: #AF5F00 +} + +div.highlight .-Color[class*=-BGC130] { + background-color: #AF5F00 +} + +div.highlight .-Color[class*=-C131] { + color: #AF5F5F +} + +div.highlight .-Color[class*=-BGC131] { + background-color: #AF5F5F +} + +div.highlight .-Color[class*=-C132] { + color: #AF5F87 +} + +div.highlight .-Color[class*=-BGC132] { + background-color: #AF5F87 +} + +div.highlight .-Color[class*=-C133] { + color: #AF5FAF +} + +div.highlight .-Color[class*=-BGC133] { + background-color: #AF5FAF +} + +div.highlight .-Color[class*=-C134] { + color: #AF5FD7 +} + +div.highlight .-Color[class*=-BGC134] { + background-color: #AF5FD7 +} + +div.highlight .-Color[class*=-C135] { + color: #AF5FFF +} + +div.highlight .-Color[class*=-BGC135] { + background-color: #AF5FFF +} + +div.highlight .-Color[class*=-C136] { + color: #AF8700 +} + +div.highlight .-Color[class*=-BGC136] { + background-color: #AF8700 +} + +div.highlight .-Color[class*=-C137] { + color: #AF875F +} + +div.highlight .-Color[class*=-BGC137] { + background-color: #AF875F +} + +div.highlight .-Color[class*=-C138] { + color: #AF8787 +} + +div.highlight .-Color[class*=-BGC138] { + background-color: #AF8787 +} + +div.highlight .-Color[class*=-C139] { + color: #AF87AF +} + +div.highlight .-Color[class*=-BGC139] { + background-color: #AF87AF +} + +div.highlight .-Color[class*=-C140] { + color: #AF87D7 +} + +div.highlight .-Color[class*=-BGC140] { + background-color: #AF87D7 +} + +div.highlight .-Color[class*=-C141] { + color: #AF87FF +} + +div.highlight .-Color[class*=-BGC141] { + background-color: #AF87FF +} + +div.highlight .-Color[class*=-C142] { + color: #AFAF00 +} + +div.highlight .-Color[class*=-BGC142] { + background-color: #AFAF00 +} + +div.highlight .-Color[class*=-C143] { + color: #AFAF5F +} + +div.highlight .-Color[class*=-BGC143] { + background-color: #AFAF5F +} + +div.highlight .-Color[class*=-C144] { + color: #AFAF87 +} + +div.highlight .-Color[class*=-BGC144] { + background-color: #AFAF87 +} + +div.highlight .-Color[class*=-C145] { + color: #AFAFAF +} + +div.highlight .-Color[class*=-BGC145] { + background-color: #AFAFAF +} + +div.highlight .-Color[class*=-C146] { + color: #AFAFD7 +} + +div.highlight .-Color[class*=-BGC146] { + background-color: #AFAFD7 +} + +div.highlight .-Color[class*=-C147] { + color: #AFAFFF +} + +div.highlight .-Color[class*=-BGC147] { + background-color: #AFAFFF +} + +div.highlight .-Color[class*=-C148] { + color: #AFD700 +} + +div.highlight .-Color[class*=-BGC148] { + background-color: #AFD700 +} + +div.highlight .-Color[class*=-C149] { + color: #AFD75F +} + +div.highlight .-Color[class*=-BGC149] { + background-color: #AFD75F +} + +div.highlight .-Color[class*=-C150] { + color: #AFD787 +} + +div.highlight .-Color[class*=-BGC150] { + background-color: #AFD787 +} + +div.highlight .-Color[class*=-C151] { + color: #AFD7AF +} + +div.highlight .-Color[class*=-BGC151] { + background-color: #AFD7AF +} + +div.highlight .-Color[class*=-C152] { + color: #AFD7D7 +} + +div.highlight .-Color[class*=-BGC152] { + background-color: #AFD7D7 +} + +div.highlight .-Color[class*=-C153] { + color: #AFD7FF +} + +div.highlight .-Color[class*=-BGC153] { + background-color: #AFD7FF +} + +div.highlight .-Color[class*=-C154] { + color: #AFFF00 +} + +div.highlight .-Color[class*=-BGC154] { + background-color: #AFFF00 +} + +div.highlight .-Color[class*=-C155] { + color: #AFFF5F +} + +div.highlight .-Color[class*=-BGC155] { + background-color: #AFFF5F +} + +div.highlight .-Color[class*=-C156] { + color: #AFFF87 +} + +div.highlight .-Color[class*=-BGC156] { + background-color: #AFFF87 +} + +div.highlight .-Color[class*=-C157] { + color: #AFFFAF +} + +div.highlight .-Color[class*=-BGC157] { + background-color: #AFFFAF +} + +div.highlight .-Color[class*=-C158] { + color: #AFFFD7 +} + +div.highlight .-Color[class*=-BGC158] { + background-color: #AFFFD7 +} + +div.highlight .-Color[class*=-C159] { + color: #AFFFFF +} + +div.highlight .-Color[class*=-BGC159] { + background-color: #AFFFFF +} + +div.highlight .-Color[class*=-C160] { + color: #D70000 +} + +div.highlight .-Color[class*=-BGC160] { + background-color: #D70000 +} + +div.highlight .-Color[class*=-C161] { + color: #D7005F +} + +div.highlight .-Color[class*=-BGC161] { + background-color: #D7005F +} + +div.highlight .-Color[class*=-C162] { + color: #D70087 +} + +div.highlight .-Color[class*=-BGC162] { + background-color: #D70087 +} + +div.highlight .-Color[class*=-C163] { + color: #D700AF +} + +div.highlight .-Color[class*=-BGC163] { + background-color: #D700AF +} + +div.highlight .-Color[class*=-C164] { + color: #D700D7 +} + +div.highlight .-Color[class*=-BGC164] { + background-color: #D700D7 +} + +div.highlight .-Color[class*=-C165] { + color: #D700FF +} + +div.highlight .-Color[class*=-BGC165] { + background-color: #D700FF +} + +div.highlight .-Color[class*=-C166] { + color: #D75F00 +} + +div.highlight .-Color[class*=-BGC166] { + background-color: #D75F00 +} + +div.highlight .-Color[class*=-C167] { + color: #D75F5F +} + +div.highlight .-Color[class*=-BGC167] { + background-color: #D75F5F +} + +div.highlight .-Color[class*=-C168] { + color: #D75F87 +} + +div.highlight .-Color[class*=-BGC168] { + background-color: #D75F87 +} + +div.highlight .-Color[class*=-C169] { + color: #D75FAF +} + +div.highlight .-Color[class*=-BGC169] { + background-color: #D75FAF +} + +div.highlight .-Color[class*=-C170] { + color: #D75FD7 +} + +div.highlight .-Color[class*=-BGC170] { + background-color: #D75FD7 +} + +div.highlight .-Color[class*=-C171] { + color: #D75FFF +} + +div.highlight .-Color[class*=-BGC171] { + background-color: #D75FFF +} + +div.highlight .-Color[class*=-C172] { + color: #D78700 +} + +div.highlight .-Color[class*=-BGC172] { + background-color: #D78700 +} + +div.highlight .-Color[class*=-C173] { + color: #D7875F +} + +div.highlight .-Color[class*=-BGC173] { + background-color: #D7875F +} + +div.highlight .-Color[class*=-C174] { + color: #D78787 +} + +div.highlight .-Color[class*=-BGC174] { + background-color: #D78787 +} + +div.highlight .-Color[class*=-C175] { + color: #D787AF +} + +div.highlight .-Color[class*=-BGC175] { + background-color: #D787AF +} + +div.highlight .-Color[class*=-C176] { + color: #D787D7 +} + +div.highlight .-Color[class*=-BGC176] { + background-color: #D787D7 +} + +div.highlight .-Color[class*=-C177] { + color: #D787FF +} + +div.highlight .-Color[class*=-BGC177] { + background-color: #D787FF +} + +div.highlight .-Color[class*=-C178] { + color: #D7AF00 +} + +div.highlight .-Color[class*=-BGC178] { + background-color: #D7AF00 +} + +div.highlight .-Color[class*=-C179] { + color: #D7AF5F +} + +div.highlight .-Color[class*=-BGC179] { + background-color: #D7AF5F +} + +div.highlight .-Color[class*=-C180] { + color: #D7AF87 +} + +div.highlight .-Color[class*=-BGC180] { + background-color: #D7AF87 +} + +div.highlight .-Color[class*=-C181] { + color: #D7AFAF +} + +div.highlight .-Color[class*=-BGC181] { + background-color: #D7AFAF +} + +div.highlight .-Color[class*=-C182] { + color: #D7AFD7 +} + +div.highlight .-Color[class*=-BGC182] { + background-color: #D7AFD7 +} + +div.highlight .-Color[class*=-C183] { + color: #D7AFFF +} + +div.highlight .-Color[class*=-BGC183] { + background-color: #D7AFFF +} + +div.highlight .-Color[class*=-C184] { + color: #D7D700 +} + +div.highlight .-Color[class*=-BGC184] { + background-color: #D7D700 +} + +div.highlight .-Color[class*=-C185] { + color: #D7D75F +} + +div.highlight .-Color[class*=-BGC185] { + background-color: #D7D75F +} + +div.highlight .-Color[class*=-C186] { + color: #D7D787 +} + +div.highlight .-Color[class*=-BGC186] { + background-color: #D7D787 +} + +div.highlight .-Color[class*=-C187] { + color: #D7D7AF +} + +div.highlight .-Color[class*=-BGC187] { + background-color: #D7D7AF +} + +div.highlight .-Color[class*=-C188] { + color: #D7D7D7 +} + +div.highlight .-Color[class*=-BGC188] { + background-color: #D7D7D7 +} + +div.highlight .-Color[class*=-C189] { + color: #D7D7FF +} + +div.highlight .-Color[class*=-BGC189] { + background-color: #D7D7FF +} + +div.highlight .-Color[class*=-C190] { + color: #D7FF00 +} + +div.highlight .-Color[class*=-BGC190] { + background-color: #D7FF00 +} + +div.highlight .-Color[class*=-C191] { + color: #D7FF5F +} + +div.highlight .-Color[class*=-BGC191] { + background-color: #D7FF5F +} + +div.highlight .-Color[class*=-C192] { + color: #D7FF87 +} + +div.highlight .-Color[class*=-BGC192] { + background-color: #D7FF87 +} + +div.highlight .-Color[class*=-C193] { + color: #D7FFAF +} + +div.highlight .-Color[class*=-BGC193] { + background-color: #D7FFAF +} + +div.highlight .-Color[class*=-C194] { + color: #D7FFD7 +} + +div.highlight .-Color[class*=-BGC194] { + background-color: #D7FFD7 +} + +div.highlight .-Color[class*=-C195] { + color: #D7FFFF +} + +div.highlight .-Color[class*=-BGC195] { + background-color: #D7FFFF +} + +div.highlight .-Color[class*=-C196] { + color: #FF0000 +} + +div.highlight .-Color[class*=-BGC196] { + background-color: #FF0000 +} + +div.highlight .-Color[class*=-C197] { + color: #FF005F +} + +div.highlight .-Color[class*=-BGC197] { + background-color: #FF005F +} + +div.highlight .-Color[class*=-C198] { + color: #FF0087 +} + +div.highlight .-Color[class*=-BGC198] { + background-color: #FF0087 +} + +div.highlight .-Color[class*=-C199] { + color: #FF00AF +} + +div.highlight .-Color[class*=-BGC199] { + background-color: #FF00AF +} + +div.highlight .-Color[class*=-C200] { + color: #FF00D7 +} + +div.highlight .-Color[class*=-BGC200] { + background-color: #FF00D7 +} + +div.highlight .-Color[class*=-C201] { + color: #FF00FF +} + +div.highlight .-Color[class*=-BGC201] { + background-color: #FF00FF +} + +div.highlight .-Color[class*=-C202] { + color: #FF5F00 +} + +div.highlight .-Color[class*=-BGC202] { + background-color: #FF5F00 +} + +div.highlight .-Color[class*=-C203] { + color: #FF5F5F +} + +div.highlight .-Color[class*=-BGC203] { + background-color: #FF5F5F +} + +div.highlight .-Color[class*=-C204] { + color: #FF5F87 +} + +div.highlight .-Color[class*=-BGC204] { + background-color: #FF5F87 +} + +div.highlight .-Color[class*=-C205] { + color: #FF5FAF +} + +div.highlight .-Color[class*=-BGC205] { + background-color: #FF5FAF +} + +div.highlight .-Color[class*=-C206] { + color: #FF5FD7 +} + +div.highlight .-Color[class*=-BGC206] { + background-color: #FF5FD7 +} + +div.highlight .-Color[class*=-C207] { + color: #FF5FFF +} + +div.highlight .-Color[class*=-BGC207] { + background-color: #FF5FFF +} + +div.highlight .-Color[class*=-C208] { + color: #FF8700 +} + +div.highlight .-Color[class*=-BGC208] { + background-color: #FF8700 +} + +div.highlight .-Color[class*=-C209] { + color: #FF875F +} + +div.highlight .-Color[class*=-BGC209] { + background-color: #FF875F +} + +div.highlight .-Color[class*=-C210] { + color: #FF8787 +} + +div.highlight .-Color[class*=-BGC210] { + background-color: #FF8787 +} + +div.highlight .-Color[class*=-C211] { + color: #FF87AF +} + +div.highlight .-Color[class*=-BGC211] { + background-color: #FF87AF +} + +div.highlight .-Color[class*=-C212] { + color: #FF87D7 +} + +div.highlight .-Color[class*=-BGC212] { + background-color: #FF87D7 +} + +div.highlight .-Color[class*=-C213] { + color: #FF87FF +} + +div.highlight .-Color[class*=-BGC213] { + background-color: #FF87FF +} + +div.highlight .-Color[class*=-C214] { + color: #FFAF00 +} + +div.highlight .-Color[class*=-BGC214] { + background-color: #FFAF00 +} + +div.highlight .-Color[class*=-C215] { + color: #FFAF5F +} + +div.highlight .-Color[class*=-BGC215] { + background-color: #FFAF5F +} + +div.highlight .-Color[class*=-C216] { + color: #FFAF87 +} + +div.highlight .-Color[class*=-BGC216] { + background-color: #FFAF87 +} + +div.highlight .-Color[class*=-C217] { + color: #FFAFAF +} + +div.highlight .-Color[class*=-BGC217] { + background-color: #FFAFAF +} + +div.highlight .-Color[class*=-C218] { + color: #FFAFD7 +} + +div.highlight .-Color[class*=-BGC218] { + background-color: #FFAFD7 +} + +div.highlight .-Color[class*=-C219] { + color: #FFAFFF +} + +div.highlight .-Color[class*=-BGC219] { + background-color: #FFAFFF +} + +div.highlight .-Color[class*=-C220] { + color: #FFD700 +} + +div.highlight .-Color[class*=-BGC220] { + background-color: #FFD700 +} + +div.highlight .-Color[class*=-C221] { + color: #FFD75F +} + +div.highlight .-Color[class*=-BGC221] { + background-color: #FFD75F +} + +div.highlight .-Color[class*=-C222] { + color: #FFD787 +} + +div.highlight .-Color[class*=-BGC222] { + background-color: #FFD787 +} + +div.highlight .-Color[class*=-C223] { + color: #FFD7AF +} + +div.highlight .-Color[class*=-BGC223] { + background-color: #FFD7AF +} + +div.highlight .-Color[class*=-C224] { + color: #FFD7D7 +} + +div.highlight .-Color[class*=-BGC224] { + background-color: #FFD7D7 +} + +div.highlight .-Color[class*=-C225] { + color: #FFD7FF +} + +div.highlight .-Color[class*=-BGC225] { + background-color: #FFD7FF +} + +div.highlight .-Color[class*=-C226] { + color: #FFFF00 +} + +div.highlight .-Color[class*=-BGC226] { + background-color: #FFFF00 +} + +div.highlight .-Color[class*=-C227] { + color: #FFFF5F +} + +div.highlight .-Color[class*=-BGC227] { + background-color: #FFFF5F +} + +div.highlight .-Color[class*=-C228] { + color: #FFFF87 +} + +div.highlight .-Color[class*=-BGC228] { + background-color: #FFFF87 +} + +div.highlight .-Color[class*=-C229] { + color: #FFFFAF +} + +div.highlight .-Color[class*=-BGC229] { + background-color: #FFFFAF +} + +div.highlight .-Color[class*=-C230] { + color: #FFFFD7 +} + +div.highlight .-Color[class*=-BGC230] { + background-color: #FFFFD7 +} + +div.highlight .-Color[class*=-C231] { + color: #FFFFFF +} + +div.highlight .-Color[class*=-BGC231] { + background-color: #FFFFFF +} + +div.highlight .-Color[class*=-C232] { + color: #080808 +} + +div.highlight .-Color[class*=-BGC232] { + background-color: #080808 +} + +div.highlight .-Color[class*=-C233] { + color: #121212 +} + +div.highlight .-Color[class*=-BGC233] { + background-color: #121212 +} + +div.highlight .-Color[class*=-C234] { + color: #1C1C1C +} + +div.highlight .-Color[class*=-BGC234] { + background-color: #1C1C1C +} + +div.highlight .-Color[class*=-C235] { + color: #262626 +} + +div.highlight .-Color[class*=-BGC235] { + background-color: #262626 +} + +div.highlight .-Color[class*=-C236] { + color: #303030 +} + +div.highlight .-Color[class*=-BGC236] { + background-color: #303030 +} + +div.highlight .-Color[class*=-C237] { + color: #3A3A3A +} + +div.highlight .-Color[class*=-BGC237] { + background-color: #3A3A3A +} + +div.highlight .-Color[class*=-C238] { + color: #444444 +} + +div.highlight .-Color[class*=-BGC238] { + background-color: #444444 +} + +div.highlight .-Color[class*=-C239] { + color: #4E4E4E +} + +div.highlight .-Color[class*=-BGC239] { + background-color: #4E4E4E +} + +div.highlight .-Color[class*=-C240] { + color: #585858 +} + +div.highlight .-Color[class*=-BGC240] { + background-color: #585858 +} + +div.highlight .-Color[class*=-C241] { + color: #626262 +} + +div.highlight .-Color[class*=-BGC241] { + background-color: #626262 +} + +div.highlight .-Color[class*=-C242] { + color: #6C6C6C +} + +div.highlight .-Color[class*=-BGC242] { + background-color: #6C6C6C +} + +div.highlight .-Color[class*=-C243] { + color: #767676 +} + +div.highlight .-Color[class*=-BGC243] { + background-color: #767676 +} + +div.highlight .-Color[class*=-C244] { + color: #808080 +} + +div.highlight .-Color[class*=-BGC244] { + background-color: #808080 +} + +div.highlight .-Color[class*=-C245] { + color: #8A8A8A +} + +div.highlight .-Color[class*=-BGC245] { + background-color: #8A8A8A +} + +div.highlight .-Color[class*=-C246] { + color: #949494 +} + +div.highlight .-Color[class*=-BGC246] { + background-color: #949494 +} + +div.highlight .-Color[class*=-C247] { + color: #9E9E9E +} + +div.highlight .-Color[class*=-BGC247] { + background-color: #9E9E9E +} + +div.highlight .-Color[class*=-C248] { + color: #A8A8A8 +} + +div.highlight .-Color[class*=-BGC248] { + background-color: #A8A8A8 +} + +div.highlight .-Color[class*=-C249] { + color: #B2B2B2 +} + +div.highlight .-Color[class*=-BGC249] { + background-color: #B2B2B2 +} + +div.highlight .-Color[class*=-C250] { + color: #BCBCBC +} + +div.highlight .-Color[class*=-BGC250] { + background-color: #BCBCBC +} + +div.highlight .-Color[class*=-C251] { + color: #C6C6C6 +} + +div.highlight .-Color[class*=-BGC251] { + background-color: #C6C6C6 +} + +div.highlight .-Color[class*=-C252] { + color: #D0D0D0 +} + +div.highlight .-Color[class*=-BGC252] { + background-color: #D0D0D0 +} + +div.highlight .-Color[class*=-C253] { + color: #DADADA +} + +div.highlight .-Color[class*=-BGC253] { + background-color: #DADADA +} + +div.highlight .-Color[class*=-C254] { + color: #E4E4E4 +} + +div.highlight .-Color[class*=-BGC254] { + background-color: #E4E4E4 +} + +div.highlight .-Color[class*=-C255] { + color: #EEEEEE +} + +div.highlight .-Color[class*=-BGC255] { + background-color: #EEEEEE +} diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 000000000..7107cec93 Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 000000000..84ab3030a --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 000000000..b08d58c9b --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,620 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlink", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + const score = Math.round(Scorer.title * queryLower.length / title.length); + const boost = titles[file] === title ? 1 : 0; // add a boost for document titles + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score + boost, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 000000000..8a96c69a1 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/_static/sphinx_lesson.css b/_static/sphinx_lesson.css new file mode 100644 index 000000000..14b20c644 --- /dev/null +++ b/_static/sphinx_lesson.css @@ -0,0 +1,51 @@ +/* sphinx_lesson.css */ + +body.wy-body-for-nav img.with-border { + border: 2px solid; +} + +.rst-content .admonition-no-content { + padding-bottom: 0px; +} + +.rst-content .demo > .admonition-title::before { + content: "\01F440"; /* Eyes */ } +.rst-content .type-along > .admonition-title::before { + content: "\02328\0FE0F"; /* Keyboard */ } +.rst-content .exercise > .admonition-title::before { + content: "\0270D\0FE0F"; /* Hand */ } +.rst-content .solution > .admonition-title::before { + content: "\02714\0FE0E"; /* Check mark */ } +.rst-content .homework > .admonition-title::before { + content: "\01F4DD"; /* Memo */ } +.rst-content .discussion > .admonition-title::before { + content: "\01F4AC"; /* Speech balloon */ } +.rst-content .questions > .admonition-title::before { + content: "\02753\0FE0E"; /* Question mark */ } +.rst-content .prerequisites > .admonition-title::before { + content: "\02699"; /* Gear */ } +.rst-content .seealso > .admonition-title::before { + content: "\027A1\0FE0E"; /* Question mark */ } + + +/* instructor-note */ +.rst-content .instructor-note { + background: #e7e7e7; +} +.rst-content .instructor-note > .admonition-title { + background: #6a6a6a; +} +.rst-content .instructor-note > .admonition-title::before { + content: ""; +} + + +/* sphinx_toggle_button, make the font white */ +.rst-content .toggle.admonition button.toggle-button { + color: white; +} + +/* sphinx-togglebutton, remove underflow when toggled to hidden mode */ +.rst-content .admonition.toggle-hidden { + padding-bottom: 0px; +} diff --git a/_static/tabs.css b/_static/tabs.css new file mode 100644 index 000000000..957ba60d6 --- /dev/null +++ b/_static/tabs.css @@ -0,0 +1,89 @@ +.sphinx-tabs { + margin-bottom: 1rem; +} + +[role="tablist"] { + border-bottom: 1px solid #a0b3bf; +} + +.sphinx-tabs-tab { + position: relative; + font-family: Lato,'Helvetica Neue',Arial,Helvetica,sans-serif; + color: #1D5C87; + line-height: 24px; + margin: 0; + font-size: 16px; + font-weight: 400; + background-color: rgba(255, 255, 255, 0); + border-radius: 5px 5px 0 0; + border: 0; + padding: 1rem 1.5rem; + margin-bottom: 0; +} + +.sphinx-tabs-tab[aria-selected="true"] { + font-weight: 700; + border: 1px solid #a0b3bf; + border-bottom: 1px solid white; + margin: -1px; + background-color: white; +} + +.sphinx-tabs-tab:focus { + z-index: 1; + outline-offset: 1px; +} + +.sphinx-tabs-panel { + position: relative; + padding: 1rem; + border: 1px solid #a0b3bf; + margin: 0px -1px -1px -1px; + border-radius: 0 0 5px 5px; + border-top: 0; + background: white; +} + +.sphinx-tabs-panel.code-tab { + padding: 0.4rem; +} + +.sphinx-tab img { + margin-bottom: 24 px; +} + +/* Dark theme preference styling */ + +@media (prefers-color-scheme: dark) { + body[data-theme="auto"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); + } + + body[data-theme="auto"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); + } + + body[data-theme="auto"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 1px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); + } +} + +/* Explicit dark theme styling */ + +body[data-theme="dark"] .sphinx-tabs-panel { + color: white; + background-color: rgb(50, 50, 50); +} + +body[data-theme="dark"] .sphinx-tabs-tab { + color: white; + background-color: rgba(255, 255, 255, 0.05); +} + +body[data-theme="dark"] .sphinx-tabs-tab[aria-selected="true"] { + border-bottom: 2px solid rgb(50, 50, 50); + background-color: rgb(50, 50, 50); +} diff --git a/_static/tabs.js b/_static/tabs.js new file mode 100644 index 000000000..48dc303c8 --- /dev/null +++ b/_static/tabs.js @@ -0,0 +1,145 @@ +try { + var session = window.sessionStorage || {}; +} catch (e) { + var session = {}; +} + +window.addEventListener("DOMContentLoaded", () => { + const allTabs = document.querySelectorAll('.sphinx-tabs-tab'); + const tabLists = document.querySelectorAll('[role="tablist"]'); + + allTabs.forEach(tab => { + tab.addEventListener("click", changeTabs); + }); + + tabLists.forEach(tabList => { + tabList.addEventListener("keydown", keyTabs); + }); + + // Restore group tab selection from session + const lastSelected = session.getItem('sphinx-tabs-last-selected'); + if (lastSelected != null) selectNamedTabs(lastSelected); +}); + +/** + * Key focus left and right between sibling elements using arrows + * @param {Node} e the element in focus when key was pressed + */ +function keyTabs(e) { + const tab = e.target; + let nextTab = null; + if (e.keyCode === 39 || e.keyCode === 37) { + tab.setAttribute("tabindex", -1); + // Move right + if (e.keyCode === 39) { + nextTab = tab.nextElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.firstElementChild; + } + // Move left + } else if (e.keyCode === 37) { + nextTab = tab.previousElementSibling; + if (nextTab === null) { + nextTab = tab.parentNode.lastElementChild; + } + } + } + + if (nextTab !== null) { + nextTab.setAttribute("tabindex", 0); + nextTab.focus(); + } +} + +/** + * Select or deselect clicked tab. If a group tab + * is selected, also select tab in other tabLists. + * @param {Node} e the element that was clicked + */ +function changeTabs(e) { + // Use this instead of the element that was clicked, in case it's a child + const notSelected = this.getAttribute("aria-selected") === "false"; + const positionBefore = this.parentNode.getBoundingClientRect().top; + const notClosable = !this.parentNode.classList.contains("closeable"); + + deselectTabList(this); + + if (notSelected || notClosable) { + selectTab(this); + const name = this.getAttribute("name"); + selectNamedTabs(name, this.id); + + if (this.classList.contains("group-tab")) { + // Persist during session + session.setItem('sphinx-tabs-last-selected', name); + } + } + + const positionAfter = this.parentNode.getBoundingClientRect().top; + const positionDelta = positionAfter - positionBefore; + // Scroll to offset content resizing + window.scrollTo(0, window.scrollY + positionDelta); +} + +/** + * Select tab and show associated panel. + * @param {Node} tab tab to select + */ +function selectTab(tab) { + tab.setAttribute("aria-selected", true); + + // Show the associated panel + document + .getElementById(tab.getAttribute("aria-controls")) + .removeAttribute("hidden"); +} + +/** + * Hide the panels associated with all tabs within the + * tablist containing this tab. + * @param {Node} tab a tab within the tablist to deselect + */ +function deselectTabList(tab) { + const parent = tab.parentNode; + const grandparent = parent.parentNode; + + Array.from(parent.children) + .forEach(t => t.setAttribute("aria-selected", false)); + + Array.from(grandparent.children) + .slice(1) // Skip tablist + .forEach(panel => panel.setAttribute("hidden", true)); +} + +/** + * Select grouped tabs with the same name, but no the tab + * with the given id. + * @param {Node} name name of grouped tab to be selected + * @param {Node} clickedId id of clicked tab + */ +function selectNamedTabs(name, clickedId=null) { + const groupedTabs = document.querySelectorAll(`.sphinx-tabs-tab[name="${name}"]`); + const tabLists = Array.from(groupedTabs).map(tab => tab.parentNode); + + tabLists + .forEach(tabList => { + // Don't want to change the tabList containing the clicked tab + const clickedTab = tabList.querySelector(`[id="${clickedId}"]`); + if (clickedTab === null ) { + // Select first tab with matching name + const tab = tabList.querySelector(`.sphinx-tabs-tab[name="${name}"]`); + deselectTabList(tab); + selectTab(tab); + } + }) +} + +if (typeof exports === 'undefined') { + exports = {}; +} + +exports.keyTabs = keyTabs; +exports.changeTabs = changeTabs; +exports.selectTab = selectTab; +exports.deselectTabList = deselectTabList; +exports.selectNamedTabs = selectNamedTabs; diff --git a/_static/term_role_formatting.css b/_static/term_role_formatting.css new file mode 100644 index 000000000..0b66095c7 --- /dev/null +++ b/_static/term_role_formatting.css @@ -0,0 +1,4 @@ +/* Make terms bold */ +a.reference span.std-term { + font-weight: bold; +} diff --git a/_static/togglebutton.css b/_static/togglebutton.css new file mode 100644 index 000000000..54a678790 --- /dev/null +++ b/_static/togglebutton.css @@ -0,0 +1,160 @@ +/** + * Admonition-based toggles + */ + +/* Visibility of the target */ +.admonition.toggle .admonition-title ~ * { + transition: opacity .3s, height .3s; +} + +/* Toggle buttons inside admonitions so we see the title */ +.admonition.toggle { + position: relative; +} + +/* Titles should cut off earlier to avoid overlapping w/ button */ +.admonition.toggle .admonition-title { + padding-right: 25%; + cursor: pointer; +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:hover { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 1%); +} + +/* Hovering will cause a slight shift in color to make it feel interactive */ +.admonition.toggle .admonition-title:active { + box-shadow: inset 0 0 0px 20px rgb(0 0 0 / 3%); +} + +/* Remove extra whitespace below the admonition title when hidden */ +.admonition.toggle-hidden { + padding-bottom: 0; +} + +.admonition.toggle-hidden .admonition-title { + margin-bottom: 0; +} + +/* hides all the content of a page until de-toggled */ +.admonition.toggle-hidden .admonition-title ~ * { + height: 0; + margin: 0; + opacity: 0; + visibility: hidden; +} + +/* General button style and position*/ +button.toggle-button { + /** + * Background and shape. By default there's no background + * but users can style as they wish + */ + background: none; + border: none; + outline: none; + + /* Positioning just inside the admonition title */ + position: absolute; + right: 0.5em; + padding: 0px; + border: none; + outline: none; +} + +/* Display the toggle hint on wide screens */ +@media (min-width: 768px) { + button.toggle-button.toggle-button-hidden:before { + content: attr(data-toggle-hint); /* This will be filled in by JS */ + font-size: .8em; + align-self: center; + } +} + +/* Icon behavior */ +.tb-icon { + transition: transform .2s ease-out; + height: 1.5em; + width: 1.5em; + stroke: currentColor; /* So that we inherit the color of other text */ +} + +/* The icon should point right when closed, down when open. */ +/* Open */ +.admonition.toggle button .tb-icon { + transform: rotate(90deg); +} + +/* Closed */ +.admonition.toggle button.toggle-button-hidden .tb-icon { + transform: rotate(0deg); +} + +/* With details toggles, we don't rotate the icon so it points right */ +details.toggle-details .tb-icon { + height: 1.4em; + width: 1.4em; + margin-top: 0.1em; /* To center the button vertically */ +} + + +/** + * Details-based toggles. + * In this case, we wrap elements with `.toggle` in a details block. + */ + +/* Details blocks */ +details.toggle-details { + margin: 1em 0; +} + + +details.toggle-details summary { + display: flex; + align-items: center; + cursor: pointer; + list-style: none; + border-radius: .2em; + border-left: 3px solid #1976d2; + background-color: rgb(204 204 204 / 10%); + padding: 0.2em 0.7em 0.3em 0.5em; /* Less padding on left because the SVG has left margin */ + font-size: 0.9em; +} + +details.toggle-details summary:hover { + background-color: rgb(204 204 204 / 20%); +} + +details.toggle-details summary:active { + background: rgb(204 204 204 / 28%); +} + +.toggle-details__summary-text { + margin-left: 0.2em; +} + +details.toggle-details[open] summary { + margin-bottom: .5em; +} + +details.toggle-details[open] summary .tb-icon { + transform: rotate(90deg); +} + +details.toggle-details[open] summary ~ * { + animation: toggle-fade-in .3s ease-out; +} + +@keyframes toggle-fade-in { + from {opacity: 0%;} + to {opacity: 100%;} +} + +/* Print rules - we hide all toggle button elements at print */ +@media print { + /* Always hide the summary so the button doesn't show up */ + details.toggle-details summary { + display: none; + } +} \ No newline at end of file diff --git a/_static/togglebutton.js b/_static/togglebutton.js new file mode 100644 index 000000000..215a7eef4 --- /dev/null +++ b/_static/togglebutton.js @@ -0,0 +1,187 @@ +/** + * Add Toggle Buttons to elements + */ + +let toggleChevron = ` + + + +`; + +var initToggleItems = () => { + var itemsToToggle = document.querySelectorAll(togglebuttonSelector); + console.log(`[togglebutton]: Adding toggle buttons to ${itemsToToggle.length} items`) + // Add the button to each admonition and hook up a callback to toggle visibility + itemsToToggle.forEach((item, index) => { + if (item.classList.contains("admonition")) { + // If it's an admonition block, then we'll add a button inside + // Generate unique IDs for this item + var toggleID = `toggle-${index}`; + var buttonID = `button-${toggleID}`; + + item.setAttribute('id', toggleID); + if (!item.classList.contains("toggle")){ + item.classList.add("toggle"); + } + // This is the button that will be added to each item to trigger the toggle + var collapseButton = ` + `; + + title = item.querySelector(".admonition-title") + title.insertAdjacentHTML("beforeend", collapseButton); + thisButton = document.getElementById(buttonID); + + // Add click handlers for the button + admonition title (if admonition) + admonitionTitle = document.querySelector(`#${toggleID} > .admonition-title`) + if (admonitionTitle) { + // If an admonition, then make the whole title block clickable + admonitionTitle.addEventListener('click', toggleClickHandler); + admonitionTitle.dataset.target = toggleID + admonitionTitle.dataset.button = buttonID + } else { + // If not an admonition then we'll listen for the button click + thisButton.addEventListener('click', toggleClickHandler); + } + + // Now hide the item for this toggle button unless explicitly noted to show + if (!item.classList.contains("toggle-shown")) { + toggleHidden(thisButton); + } + } else { + // If not an admonition, wrap the block in a
block + // Define the structure of the details block and insert it as a sibling + var detailsBlock = ` +
+ + ${toggleChevron} + ${toggleHintShow} + +
`; + item.insertAdjacentHTML("beforebegin", detailsBlock); + + // Now move the toggle-able content inside of the details block + details = item.previousElementSibling + details.appendChild(item) + item.classList.add("toggle-details__container") + + // Set up a click trigger to change the text as needed + details.addEventListener('click', (click) => { + let parent = click.target.parentElement; + if (parent.tagName.toLowerCase() == "details") { + summary = parent.querySelector("summary"); + details = parent; + } else { + summary = parent; + details = parent.parentElement; + } + // Update the inner text for the proper hint + if (details.open) { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintShow; + } else { + summary.querySelector("span.toggle-details__summary-text").innerText = toggleHintHide; + } + + }); + + // If we have a toggle-shown class, open details block should be open + if (item.classList.contains("toggle-shown")) { + details.click(); + } + } + }) +}; + +// This should simply add / remove the collapsed class and change the button text +var toggleHidden = (button) => { + target = button.dataset['target'] + var itemToToggle = document.getElementById(target); + if (itemToToggle.classList.contains("toggle-hidden")) { + itemToToggle.classList.remove("toggle-hidden"); + button.classList.remove("toggle-button-hidden"); + } else { + itemToToggle.classList.add("toggle-hidden"); + button.classList.add("toggle-button-hidden"); + } +} + +var toggleClickHandler = (click) => { + // Be cause the admonition title is clickable and extends to the whole admonition + // We only look for a click event on this title to trigger the toggle. + + if (click.target.classList.contains("admonition-title")) { + button = click.target.querySelector(".toggle-button"); + } else if (click.target.classList.contains("tb-icon")) { + // We've clicked the icon and need to search up one parent for the button + button = click.target.parentElement; + } else if (click.target.tagName == "polyline") { + // We've clicked the SVG elements inside the button, need to up 2 layers + button = click.target.parentElement.parentElement; + } else if (click.target.classList.contains("toggle-button")) { + // We've clicked the button itself and so don't need to do anything + button = click.target; + } else { + console.log(`[togglebutton]: Couldn't find button for ${click.target}`) + } + target = document.getElementById(button.dataset['button']); + toggleHidden(target); +} + +// If we want to blanket-add toggle classes to certain cells +var addToggleToSelector = () => { + const selector = ""; + if (selector.length > 0) { + document.querySelectorAll(selector).forEach((item) => { + item.classList.add("toggle"); + }) + } +} + +// Helper function to run when the DOM is finished +const sphinxToggleRunWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} +sphinxToggleRunWhenDOMLoaded(addToggleToSelector) +sphinxToggleRunWhenDOMLoaded(initToggleItems) + +/** Toggle details blocks to be open when printing */ +if (toggleOpenOnPrint == "true") { + window.addEventListener("beforeprint", () => { + // Open the details + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.dataset["togglestatus"] = el.open; + el.open = true; + }); + + // Open the admonitions + document.querySelectorAll(".admonition.toggle.toggle-hidden").forEach((el) => { + console.log(el); + el.querySelector("button.toggle-button").click(); + el.dataset["toggle_after_print"] = "true"; + }); + }); + window.addEventListener("afterprint", () => { + // Re-close the details that were closed + document.querySelectorAll("details.toggle-details").forEach((el) => { + el.open = el.dataset["togglestatus"] == "true"; + delete el.dataset["togglestatus"]; + }); + + // Re-close the admonition toggle buttons + document.querySelectorAll(".admonition.toggle").forEach((el) => { + if (el.dataset["toggle_after_print"] == "true") { + el.querySelector("button.toggle-button").click(); + delete el.dataset["toggle_after_print"]; + } + }); + }); +} diff --git a/api.html b/api.html new file mode 100644 index 000000000..7822e440c --- /dev/null +++ b/api.html @@ -0,0 +1,157 @@ + + + + + + + API Reference — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

API Reference

+ + + + + + + + + +

iblrig

iblrig_tasks

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.ActiveChoiceWorldSession.html b/api/iblrig.base_choice_world.ActiveChoiceWorldSession.html new file mode 100644 index 000000000..aa73c2223 --- /dev/null +++ b/api/iblrig.base_choice_world.ActiveChoiceWorldSession.html @@ -0,0 +1,272 @@ + + + + + + + iblrig.base_choice_world.ActiveChoiceWorldSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.ActiveChoiceWorldSession

+
Inheritance diagram of ActiveChoiceWorldSession
+ + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig.base_choice_world.ActiveChoiceWorldSession[source]
+

The ActiveChoiceWorldSession is a base class for protocols where the mouse is actively making decisions +by turning the wheel. It has the following characteristics

+
    +
  • it is trial based

  • +
  • it is decision based

  • +
  • left and right simulus are equiprobable: there is no biased block

  • +
  • a trial can either be correct / error / no_go depending on the side of the stimulus and the response

  • +
  • it has a quantifiable performance by computing the proportion of correct trials of passive stimulations protocols or +habituation protocols.

  • +
+

The TrainingChoiceWorld, BiasedChoiceWorld are all subclasses of this class

+
+
+TrialDataModel
+

alias of ActiveChoiceWorldTrialData

+
+ +
+
+__init__(**kwargs)[source]
+
+ +
+
+show_trial_log(extra_info=None, log_level=20)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+trial_completed(bpod_data)[source]
+

The purpose of this method is to

+
    +
  • update the trials table with information about the behaviour coming from the bpod +Constraints on the state machine data:

  • +
  • mandatory states: [‘correct’, ‘error’, ‘no_go’, ‘reward’]

  • +
  • optional states : [‘omit_correct’, ‘omit_error’, ‘omit_no_go’]

  • +
+
+
Parameters:
+

bpod_data

+
+
Returns:
+

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.html b/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.html new file mode 100644 index 000000000..2e59523b5 --- /dev/null +++ b/api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.html @@ -0,0 +1,241 @@ + + + + + + + iblrig.base_choice_world.ActiveChoiceWorldTrialData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.ActiveChoiceWorldTrialData

+
Inheritance diagram of ActiveChoiceWorldTrialData
+ + + + +
+

+
+
+
+class iblrig.base_choice_world.ActiveChoiceWorldTrialData[source]
+

Pydantic Model for Trial Data, extended from ChoiceWorldTrialData.

+
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'contrast': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'pause_duration': FieldInfo(annotation=float, required=False, default=0.0, metadata=[Ge(ge=0)]), 'position': FieldInfo(annotation=float, required=True), 'quiescent_period': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'response_side': FieldInfo(annotation=int, required=True, metadata=[Interval(gt=None, ge=-1, lt=None, le=1)]), 'response_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_amount': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_valve_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_angle': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=-180.0, lt=None, le=180.0)]), 'stim_freq': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_gain': FieldInfo(annotation=float, required=True), 'stim_phase': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]), 'stim_probability_left': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'stim_reverse': FieldInfo(annotation=bool, required=True), 'stim_sigma': FieldInfo(annotation=float, required=True), 'trial_correct': FieldInfo(annotation=bool, required=True), 'trial_num': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+response_side: Annotated[int, Interval(gt=None, ge=-1, lt=None, le=1)]
+
+ +
+
+response_time: Annotated[float, Ge(ge=0)]
+
+ +
+
+trial_correct: bool
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.BiasedChoiceWorldSession.html b/api/iblrig.base_choice_world.BiasedChoiceWorldSession.html new file mode 100644 index 000000000..1dfd53071 --- /dev/null +++ b/api/iblrig.base_choice_world.BiasedChoiceWorldSession.html @@ -0,0 +1,275 @@ + + + + + + + iblrig.base_choice_world.BiasedChoiceWorldSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.BiasedChoiceWorldSession

+
Inheritance diagram of BiasedChoiceWorldSession
+ + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig.base_choice_world.BiasedChoiceWorldSession[source]
+

Biased choice world session is the instantiation of ActiveChoiceWorld where the notion of biased +blocks is introduced.

+
+
+TrialDataModel
+

alias of BiasedChoiceWorldTrialData

+
+ +
+
+__init__(**kwargs)[source]
+
+ +
+
+new_block()[source]
+
+
if block_init_5050

First block has 50/50 probability of leftward stim +is 90 trials long

+
+
+
+ +
+
+next_trial()[source]
+
+ +
+
+show_trial_log(extra_info=None, log_level=20)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+base_parameters_file: Path | None = PosixPath('/home/runner/work/iblrig/iblrig/iblrig/base_biased_choice_world_params.yaml')
+

A YAML file containing base, default task parameters.

+
+
Type:
+

Path

+
+
+
+ +
+
+protocol_name = '_iblrig_tasks_biasedChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.html b/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.html new file mode 100644 index 000000000..f81f41ee3 --- /dev/null +++ b/api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.html @@ -0,0 +1,237 @@ + + + + + + + iblrig.base_choice_world.BiasedChoiceWorldTrialData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.BiasedChoiceWorldTrialData

+
Inheritance diagram of BiasedChoiceWorldTrialData
+ + + + + +
+

+
+
+
+class iblrig.base_choice_world.BiasedChoiceWorldTrialData[source]
+

Pydantic Model for Trial Data, extended from ChoiceWorldTrialData.

+
+
+block_num: Annotated[int, Ge(ge=0)]
+
+ +
+
+block_trial_num: Annotated[int, Ge(ge=0)]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'block_num': FieldInfo(annotation=int, required=False, default=0, metadata=[Ge(ge=0)]), 'block_trial_num': FieldInfo(annotation=int, required=False, default=0, metadata=[Ge(ge=0)]), 'contrast': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'pause_duration': FieldInfo(annotation=float, required=False, default=0.0, metadata=[Ge(ge=0)]), 'position': FieldInfo(annotation=float, required=True), 'quiescent_period': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'response_side': FieldInfo(annotation=int, required=True, metadata=[Interval(gt=None, ge=-1, lt=None, le=1)]), 'response_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_amount': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_valve_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_angle': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=-180.0, lt=None, le=180.0)]), 'stim_freq': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_gain': FieldInfo(annotation=float, required=True), 'stim_phase': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]), 'stim_probability_left': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'stim_reverse': FieldInfo(annotation=bool, required=True), 'stim_sigma': FieldInfo(annotation=float, required=True), 'trial_correct': FieldInfo(annotation=bool, required=True), 'trial_num': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.ChoiceWorldSession.html b/api/iblrig.base_choice_world.ChoiceWorldSession.html new file mode 100644 index 000000000..9d5383e2b --- /dev/null +++ b/api/iblrig.base_choice_world.ChoiceWorldSession.html @@ -0,0 +1,381 @@ + + + + + + + iblrig.base_choice_world.ChoiceWorldSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.ChoiceWorldSession

+
Inheritance diagram of ChoiceWorldSession
+ + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig.base_choice_world.ChoiceWorldSession[source]
+
+
+TrialDataModel
+

alias of ChoiceWorldTrialData

+
+ +
+
+__init__(*args, delay_secs=0, **kwargs)[source]
+
+ +
+
+check_sync_pulses(bpod_data)[source]
+
+ +
+
+draw_next_trial_info(pleft=0.5, **kwargs)[source]
+

Draw next trial variables.

+

calls send_trial_info_to_bonsai(). +This is called by the next_trial method before updating the Bpod state machine.

+
+ +
+
+static extra_parser()[source]
+
+
Returns:
+

argparse.parser()

+
+
+
+ +
+
+get_graphviz_task(output_file=None, view=True)[source]
+

Get the state machine’s states diagram in Digraph format.

+
+
Parameters:
+

output_file

+
+
Returns:
+

+
+
+
+ +
+
+get_state_machine_trial(i)[source]
+
+ +
+
+mock(file_jsonable_fixture=None)[source]
+

Instantiate a state machine and Bpod object to simulate a task’s run.

+

This is useful to test or display the state machine flow.

+
+ +
+
+abstract next_trial()[source]
+
+ +
+
+show_trial_log(extra_info=None, log_level=20)[source]
+

Log the details of the current trial.

+

This method retrieves information about the current trial from the +trials table and logs it. It can also incorporate additional information +provided through the extra_info parameter.

+
+
Parameters:
+
    +
  • extra_info (dict[str, Any], optional) – A dictionary containing additional information to include in the +log.

  • +
  • log_level (int, optional) – The logging level to use when logging the trial information. +Default is logging.INFO.

  • +
+
+
Parameters:
+
+
+
+
+

Notes

+

When overloading, make sure to call the super class and pass additional +log items by means of the extra_info parameter. See the implementation +of show_trial_log() in +ActiveChoiceWorldSession for reference.

+
+
+ +
+
+start_hardware()[source]
+

In this step we explicitly run the start methods of the various mixins. +The super class start method is overloaded because we need to start the different hardware pieces in order

+
+ +
+
+trial_completed(bpod_data)[source]
+
+
Parameters:
+

bpod_data (dict[str, Any])

+
+
Return type:
+

None

+
+
+
+ +
+
+base_parameters_file: Path | None = PosixPath('/home/runner/work/iblrig/iblrig/iblrig/base_choice_world_params.yaml')
+

A YAML file containing base, default task parameters.

+
+
Type:
+

Path

+
+
+
+ +
+
+property default_reward_amount
+
+ +
+
+property event_error
+
+ +
+
+property event_reward
+
+ +
+
+property iti_reward
+

Returns the ITI time that needs to be set in order to achieve the desired ITI, +by subtracting the time it takes to give a reward from the desired ITI.

+
+ +
+
+property position
+
+ +
+
+property quiescent_period
+
+ +
+
+property reward_time
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.ChoiceWorldTrialData.html b/api/iblrig.base_choice_world.ChoiceWorldTrialData.html new file mode 100644 index 000000000..8b1fec873 --- /dev/null +++ b/api/iblrig.base_choice_world.ChoiceWorldTrialData.html @@ -0,0 +1,310 @@ + + + + + + + iblrig.base_choice_world.ChoiceWorldTrialData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.ChoiceWorldTrialData

+
Inheritance diagram of ChoiceWorldTrialData
+ + + +
+

+
+
+
+class iblrig.base_choice_world.ChoiceWorldTrialData[source]
+

Pydantic Model for Trial Data.

+
+
+contrast: Annotated[float, Interval(gt=None, ge=0.0, lt=None, le=1.0)]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'contrast': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'pause_duration': FieldInfo(annotation=float, required=False, default=0.0, metadata=[Ge(ge=0)]), 'position': FieldInfo(annotation=float, required=True), 'quiescent_period': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'response_side': FieldInfo(annotation=int, required=False, default=0, metadata=[Interval(gt=None, ge=0, lt=None, le=0)]), 'response_time': FieldInfo(annotation=float, required=False, default=nan, metadata=[Predicate(math.isnan)]), 'reward_amount': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_valve_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_angle': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=-180.0, lt=None, le=180.0)]), 'stim_freq': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_gain': FieldInfo(annotation=float, required=True), 'stim_phase': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]), 'stim_probability_left': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'stim_reverse': FieldInfo(annotation=bool, required=True), 'stim_sigma': FieldInfo(annotation=float, required=True), 'trial_correct': FieldInfo(annotation=bool, required=False, default=False, metadata=[Interval(gt=None, ge=0, lt=None, le=0)]), 'trial_num': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+pause_duration: Annotated[float, Ge(ge=0)]
+
+ +
+
+position: float
+
+ +
+
+quiescent_period: Annotated[float, Ge(ge=0)]
+
+ +
+
+response_side: Annotated[int, Interval(gt=None, ge=0, lt=None, le=0)]
+
+ +
+
+response_time: Annotated[float, Predicate(func=isnan)]
+
+ +
+
+reward_amount: Annotated[float, Ge(ge=0)]
+
+ +
+
+reward_valve_time: Annotated[float, Ge(ge=0)]
+
+ +
+
+stim_angle: Annotated[float, Interval(gt=None, ge=-180.0, lt=None, le=180.0)]
+
+ +
+
+stim_freq: Annotated[float, Ge(ge=0)]
+
+ +
+
+stim_gain: float
+
+ +
+
+stim_phase: Annotated[float, Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]
+
+ +
+
+stim_probability_left: Annotated[float, Interval(gt=None, ge=0.0, lt=None, le=1.0)]
+
+ +
+
+stim_reverse: bool
+
+ +
+
+stim_sigma: float
+
+ +
+
+trial_correct: Annotated[bool, Interval(gt=None, ge=0, lt=None, le=0)]
+
+ +
+
+trial_num: Annotated[int, Ge(ge=0)]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.HabituationChoiceWorldSession.html b/api/iblrig.base_choice_world.HabituationChoiceWorldSession.html new file mode 100644 index 000000000..b096197f8 --- /dev/null +++ b/api/iblrig.base_choice_world.HabituationChoiceWorldSession.html @@ -0,0 +1,243 @@ + + + + + + + iblrig.base_choice_world.HabituationChoiceWorldSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.HabituationChoiceWorldSession

+
Inheritance diagram of HabituationChoiceWorldSession
+ + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig.base_choice_world.HabituationChoiceWorldSession[source]
+
+
+TrialDataModel
+

alias of HabituationChoiceWorldTrialData

+
+ +
+
+draw_next_trial_info(*args, **kwargs)[source]
+
+ +
+
+get_state_machine_trial(i)[source]
+
+ +
+
+next_trial()[source]
+
+ +
+
+protocol_name = '_iblrig_tasks_habituationChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.html b/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.html new file mode 100644 index 000000000..d67645532 --- /dev/null +++ b/api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.html @@ -0,0 +1,231 @@ + + + + + + + iblrig.base_choice_world.HabituationChoiceWorldTrialData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.HabituationChoiceWorldTrialData

+
Inheritance diagram of HabituationChoiceWorldTrialData
+ + + + +
+

+
+
+
+class iblrig.base_choice_world.HabituationChoiceWorldTrialData[source]
+

Pydantic Model for Trial Data, extended from ChoiceWorldTrialData.

+
+
+delay_to_stim_center: Annotated[float, Ge(ge=0)]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'contrast': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'delay_to_stim_center': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'pause_duration': FieldInfo(annotation=float, required=False, default=0.0, metadata=[Ge(ge=0)]), 'position': FieldInfo(annotation=float, required=True), 'quiescent_period': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'response_side': FieldInfo(annotation=int, required=False, default=0, metadata=[Interval(gt=None, ge=0, lt=None, le=0)]), 'response_time': FieldInfo(annotation=float, required=False, default=nan, metadata=[Predicate(math.isnan)]), 'reward_amount': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_valve_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_angle': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=-180.0, lt=None, le=180.0)]), 'stim_freq': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_gain': FieldInfo(annotation=float, required=True), 'stim_phase': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]), 'stim_probability_left': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'stim_reverse': FieldInfo(annotation=bool, required=True), 'stim_sigma': FieldInfo(annotation=float, required=True), 'trial_correct': FieldInfo(annotation=bool, required=False, default=False, metadata=[Interval(gt=None, ge=0, lt=None, le=0)]), 'trial_num': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.TrainingChoiceWorldSession.html b/api/iblrig.base_choice_world.TrainingChoiceWorldSession.html new file mode 100644 index 000000000..1196dd44d --- /dev/null +++ b/api/iblrig.base_choice_world.TrainingChoiceWorldSession.html @@ -0,0 +1,287 @@ + + + + + + + iblrig.base_choice_world.TrainingChoiceWorldSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.TrainingChoiceWorldSession

+
Inheritance diagram of TrainingChoiceWorldSession
+ + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig.base_choice_world.TrainingChoiceWorldSession[source]
+

The TrainingChoiceWorldSession corresponds to the first training protocol of the choice world task. +This protocol has a complicated adaptation of the number of contrasts (embodied by the training_phase +property) and the reward amount, embodied by the adaptive_reward property.

+
+
+TrialDataModel
+

alias of TrainingChoiceWorldTrialData

+
+ +
+
+__init__(training_phase=-1, adaptive_reward=-1.0, adaptive_gain=None, **kwargs)[source]
+
+ +
+
+check_training_phase()[source]
+

Check if the mouse is ready to move to the next training phase.

+
+ +
+
+compute_performance()[source]
+

Aggregate the trials table to compute the performance of the mouse on each contrast.

+
+ +
+
+get_subject_training_info()[source]
+

Get the previous session’s according to this session parameters and deduce the +training level, adaptive reward amount and adaptive gain value.

+
+
Returns:
+

training_info – Dictionary with keys: training_phase, adaptive_reward, adaptive_gain

+
+
Return type:
+

dict

+
+
+
+ +
+
+next_trial()[source]
+
+ +
+
+show_trial_log(extra_info=None, log_level=20)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+property default_reward_amount
+
+ +
+
+protocol_name = '_iblrig_tasks_trainingChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.html b/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.html new file mode 100644 index 000000000..80b97ef5a --- /dev/null +++ b/api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.html @@ -0,0 +1,242 @@ + + + + + + + iblrig.base_choice_world.TrainingChoiceWorldTrialData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world.TrainingChoiceWorldTrialData

+
Inheritance diagram of TrainingChoiceWorldTrialData
+ + + + + +
+

+
+
+
+class iblrig.base_choice_world.TrainingChoiceWorldTrialData[source]
+

Pydantic Model for Trial Data, extended from ActiveChoiceWorldTrialData.

+
+
+debias_trial: bool
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'contrast': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'debias_trial': FieldInfo(annotation=bool, required=True), 'pause_duration': FieldInfo(annotation=float, required=False, default=0.0, metadata=[Ge(ge=0)]), 'position': FieldInfo(annotation=float, required=True), 'quiescent_period': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'response_side': FieldInfo(annotation=int, required=True, metadata=[Interval(gt=None, ge=-1, lt=None, le=1)]), 'response_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_amount': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_valve_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'signed_contrast': FieldInfo(annotation=Union[float, NoneType], required=False, default=None), 'stim_angle': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=-180.0, lt=None, le=180.0)]), 'stim_freq': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_gain': FieldInfo(annotation=float, required=True), 'stim_phase': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]), 'stim_probability_left': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'stim_reverse': FieldInfo(annotation=bool, required=True), 'stim_sigma': FieldInfo(annotation=float, required=True), 'training_phase': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)]), 'trial_correct': FieldInfo(annotation=bool, required=True), 'trial_num': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+signed_contrast: float | None
+
+ +
+
+training_phase: Annotated[int, Ge(ge=0)]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_choice_world.html b/api/iblrig.base_choice_world.html new file mode 100644 index 000000000..f4c20d426 --- /dev/null +++ b/api/iblrig.base_choice_world.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.base_choice_world — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_choice_world

+

Extends the base_tasks modules by providing task logic around the Choice World protocol.

+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

ActiveChoiceWorldSession

The ActiveChoiceWorldSession is a base class for protocols where the mouse is actively making decisions by turning the wheel.

ActiveChoiceWorldTrialData

Pydantic Model for Trial Data, extended from ChoiceWorldTrialData.

BiasedChoiceWorldSession

Biased choice world session is the instantiation of ActiveChoiceWorld where the notion of biased blocks is introduced.

BiasedChoiceWorldTrialData

Pydantic Model for Trial Data, extended from ChoiceWorldTrialData.

ChoiceWorldSession

ChoiceWorldTrialData

Pydantic Model for Trial Data.

HabituationChoiceWorldSession

HabituationChoiceWorldTrialData

Pydantic Model for Trial Data, extended from ChoiceWorldTrialData.

TrainingChoiceWorldSession

The TrainingChoiceWorldSession corresponds to the first training protocol of the choice world task.

TrainingChoiceWorldTrialData

Pydantic Model for Trial Data, extended from ActiveChoiceWorldTrialData.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.BaseSession.html b/api/iblrig.base_tasks.BaseSession.html new file mode 100644 index 000000000..5957bdda6 --- /dev/null +++ b/api/iblrig.base_tasks.BaseSession.html @@ -0,0 +1,519 @@ + + + + + + + iblrig.base_tasks.BaseSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.BaseSession

+
Inheritance diagram of BaseSession
+ + + +
+

+
+
+
+class iblrig.base_tasks.BaseSession[source]
+
+
+__init__(subject=None, task_parameter_file=None, file_hardware_settings=None, hardware_settings=None, file_iblrig_settings=None, iblrig_settings=None, one=None, interactive=True, projects=None, procedures=None, stub=None, subject_weight_grams=None, append=False, wizard=False, log_level='INFO', **kwargs)[source]
+
+
Parameters:
+
    +
  • subject – The subject nickname. Required.

  • +
  • task_parameter_file – an optional path to the task_parameters.yaml file

  • +
  • file_hardware_settings – name of the hardware file in the settings folder, or full file path

  • +
  • hardware_settings (HardwareSettings | None) – an optional dictionary of hardware settings. Keys will override any keys in the file

  • +
  • file_iblrig_settings – name of the iblrig file in the settings folder, or full file path

  • +
  • iblrig_settings (RigSettings | None) – an optional dictionary of iblrig settings. Keys will override any keys in the file

  • +
  • one – an optional instance of ONE

  • +
  • interactive

  • +
  • projects – An optional list of Alyx protocols.

  • +
  • procedures – An optional list of Alyx procedures.

  • +
  • subject_weight_grams – weight of the subject

  • +
  • stub – A full path to an experiment description file containing experiment information.

  • +
  • append – bool, if True, append to the latest existing session of the same subject for the same day

  • +
+
+
+
+ +
+
+create_session()[source]
+

Create the session path and save json parameters in the task collection folder.

+

This will also create the protocol folder.

+
+ +
+
+static extra_parser()[source]
+

Specify extra kwargs arguments to expose to the user prior running the task.

+

Make sure you instantiate the parser.

+
+
Returns:
+

The extra parser instance.

+
+
Return type:
+

argparse.ArgumentParser

+
+
+
+ +
+
+classmethod get_task_directory()[source]
+

Get the path to the task’s directory.

+
+
Returns:
+

The path to the task’s directory.

+
+
Return type:
+

Path

+
+
+
+ +
+
+classmethod get_task_file()[source]
+

Get the path to the task’s python file.

+
+
Returns:
+

The path to the task file.

+
+
Return type:
+

Path

+
+
+
+ +
+
+static make_experiment_description_dict(task_protocol, task_collection, procedures=None, projects=None, hardware_settings=None, stub=None, extractors=None, camera_config=None)[source]
+

Construct an experiment description dictionary.

+
+
Parameters:
+
    +
  • task_protocol (str) – The task protocol name, e.g. _ibl_trainingChoiceWorld2.0.0.

  • +
  • task_collection (str) – The task collection name, e.g. raw_task_data_00.

  • +
  • procedures (list) – An optional list of Alyx procedures.

  • +
  • projects (list) – An optional list of Alyx protocols.

  • +
  • hardware_settings (dict) – An optional dict of hardware devices, loaded from the hardware_settings.yaml file.

  • +
  • stub (dict) – An optional experiment description stub to update.

  • +
  • extractors (list) – An optional list of extractor names for the task.

  • +
  • camera_config (str) – The camera configuration name in the hardware settings. Defaults to the first key in +‘device_cameras’.

  • +
+
+
Returns:
+

The experiment description.

+
+
Return type:
+

dict

+
+
Parameters:
+
+
+
+
+ +
+
+mock()[source]
+
+ +
+
+classmethod read_task_parameter_files(task_parameter_file=None)[source]
+

Get the task’s parameters from the various YAML files in the hierarchy.

+
+
Parameters:
+

task_parameter_file (str or Path, optional) – Path to override the task parameter file

+
+
Returns:
+

Task parameters

+
+
Return type:
+

Bunch

+
+
Parameters:
+

task_parameter_file (str | Path | None)

+
+
+
+ +
+
+register_to_alyx()[source]
+

Registers the session to Alyx.

+

This registers the session using the IBLRegistrationClient class. This uses the settings +file(s) and experiment description file to extract the session data. This may be called +any number of times and if the session record already exists in Alyx it will be updated. +If session registration fails, it will be done before extraction in the ibllib pipeline.

+

Note that currently the subject weight is registered once and only once. The recorded +weight of the first protocol run is used.

+

Water administrations are added separately by this method: it is expected that +register_session is first called with no recorded total water. This method will then add +a water administration each time it is called, and should therefore be called only once +after each protocol is run. If water administration registration fails for all protocols, +this will be done before extraction in the ibllib pipline, however, if a water +administration is successfully registered for one protocol and subsequent ones fail to +register, these will not be added before extraction in ibllib and therefore must be +manually added to Alyx.

+
+
Returns:
+

The registered session record.

+
+
Return type:
+

dict

+
+
+ +
+ +
+
+run()[source]
+

Common pre-run instructions for all tasks.

+

Defines sigint handler for a graceful exit.

+
+ +
+
+save_task_parameters_to_json_file(destination_folder=None)[source]
+

Collects the various settings and parameters of the session and outputs them to a JSON file.

+
+
Returns:
+

Path to the resultant JSON file

+
+
Return type:
+

Path

+
+
Parameters:
+

destination_folder (Path | None)

+
+
+
+ +
+
+final save_trial_data_to_json(bpod_data)[source]
+

Validate and save trial data.

+

This method retrieve’s the current trial’s data from the trial_table and validates it using a Pydantic model +(self.TrialDataDefinition). In merges in the trial’s bpod_data dict and appends everything to the session’s +JSON data file.

+
+
Parameters:
+

bpod_data (dict) – Trial data returned from pybpod.

+
+
Parameters:
+

bpod_data (dict)

+
+
+
+ +
+
+abstract start_hardware()[source]
+

Start the hardware.

+

This method doesn’t explicitly start the mixins as the order has to be defined in the child classes. +This needs to be implemented in the child classes, and should start and connect to all hardware pieces.

+
+ +
+
+TrialDataModel: type[TrialDataModel]
+
+ +
+
+base_parameters_file: Path | None = None
+

A YAML file containing base, default task parameters.

+
+
Type:
+

Path

+
+
+
+ +
+
+property exp_ref
+

Construct an experiment reference string from the session info attribute.

+
+ +
+
+experiment_description: dict = {}
+

The experiment description.

+
+
Type:
+

dict

+
+
+
+ +
+
+extractor_tasks: list | None = None
+

An optional list of pipeline task class names to instantiate when preprocessing task data.

+
+
Type:
+

list of str

+
+
+
+ +
+
+is_mock = False
+

One or more ibllib.pipes.tasks.Task names for task extraction.

+
+
Type:
+

list of str

+
+
+
+ +
+
+logger: Logger = None
+

Log instance used solely to keep track of log level passed to constructor.

+
+
Type:
+

logging.Logger

+
+
+
+ +
+
+property one
+

ONE getter.

+
+ +
+
+abstract property protocol_name: str
+
+ +
+
+property time_elapsed
+
+ +
+
+version = None
+

!!CURRENTLY UNUSED!! task version string.

+
+
Type:
+

str

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.BonsaiRecordingMixin.html b/api/iblrig.base_tasks.BonsaiRecordingMixin.html new file mode 100644 index 000000000..ddb238866 --- /dev/null +++ b/api/iblrig.base_tasks.BonsaiRecordingMixin.html @@ -0,0 +1,241 @@ + + + + + + + iblrig.base_tasks.BonsaiRecordingMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.BonsaiRecordingMixin

+
Inheritance diagram of BonsaiRecordingMixin
+ + + + +
+

+
+
+
+class iblrig.base_tasks.BonsaiRecordingMixin[source]
+
+
+init_mixin_bonsai_recordings(*args, **kwargs)[source]
+
+ +
+
+start_mixin_bonsai_cameras()[source]
+

Prepare the cameras.

+

Starts the pipeline that aligns the camera focus with the desired borders of rig features. +The actual triggering of the cameras is done in the trigger_bonsai_cameras method.

+
+ +
+
+start_mixin_bonsai_microphone()[source]
+
+ +
+
+stop_mixin_bonsai_recordings()[source]
+
+ +
+
+trigger_bonsai_cameras()[source]
+
+ +
+
+config: dict
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.html b/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.html new file mode 100644 index 000000000..356ecb2eb --- /dev/null +++ b/api/iblrig.base_tasks.BonsaiVisualStimulusMixin.html @@ -0,0 +1,240 @@ + + + + + + + iblrig.base_tasks.BonsaiVisualStimulusMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.BonsaiVisualStimulusMixin

+
Inheritance diagram of BonsaiVisualStimulusMixin
+ + + + +
+

+
+
+
+class iblrig.base_tasks.BonsaiVisualStimulusMixin[source]
+
+
+choice_world_visual_stimulus()[source]
+
+ +
+
+init_mixin_bonsai_visual_stimulus(*args, **kwargs)[source]
+
+ +
+
+run_passive_visual_stim(map_time='00:05:00', rate=0.1, sa_time='00:05:00')[source]
+
+ +
+
+send_trial_info_to_bonsai()[source]
+

Send the trial information to Bonsai via UDP.

+

The OSC protocol is documented in iblrig.base_tasks.BonsaiVisualStimulusMixin

+
+ +
+
+start_mixin_bonsai_visual_stimulus()[source]
+
+ +
+
+stop_mixin_bonsai_visual_stimulus()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.BpodMixin.html b/api/iblrig.base_tasks.BpodMixin.html new file mode 100644 index 000000000..604e3f704 --- /dev/null +++ b/api/iblrig.base_tasks.BpodMixin.html @@ -0,0 +1,251 @@ + + + + + + + iblrig.base_tasks.BpodMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.BpodMixin

+
Inheritance diagram of BpodMixin
+ + + + +
+

+
+
+
+class iblrig.base_tasks.BpodMixin[source]
+
+
+init_mixin_bpod(*args, **kwargs)[source]
+
+ +
+
+send_spacers()[source]
+
+ +
+
+softcode_dictionary()[source]
+

Returns a softcode handler dict where each key corresponds to the softcode and each value to the +function to be called.

+
+
This needs to be wrapped this way because
    +
  1. we want to be able to inherit this and dynamically add softcode to the dictionry

  2. +
  3. we need to provide the Task object (self) at run time to have the functions with static args

  4. +
+
+
+

This is tricky as it is unclear if the task object is a copy or a reference when passed here.

+
+
Returns:
+

Softcode dictionary

+
+
Return type:
+

OrderedDict[int, Callable]

+
+
+
+ +
+
+start_mixin_bpod()[source]
+
+ +
+
+stop_mixin_bpod()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.EmptySession.html b/api/iblrig.base_tasks.EmptySession.html new file mode 100644 index 000000000..5008257bd --- /dev/null +++ b/api/iblrig.base_tasks.EmptySession.html @@ -0,0 +1,218 @@ + + + + + + + iblrig.base_tasks.EmptySession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.EmptySession

+
Inheritance diagram of EmptySession
+ + + + +
+

+
+
+
+class iblrig.base_tasks.EmptySession[source]
+
+
+start_hardware()[source]
+
+ +
+
+protocol_name = 'empty'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.Frame2TTLMixin.html b/api/iblrig.base_tasks.Frame2TTLMixin.html new file mode 100644 index 000000000..230903504 --- /dev/null +++ b/api/iblrig.base_tasks.Frame2TTLMixin.html @@ -0,0 +1,219 @@ + + + + + + + iblrig.base_tasks.Frame2TTLMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.Frame2TTLMixin

+
Inheritance diagram of Frame2TTLMixin
+ + + + +
+

+
+
+
+class iblrig.base_tasks.Frame2TTLMixin[source]
+

Frame 2 TTL interface for state machine.

+
+
+init_mixin_frame2ttl(*args, **kwargs)[source]
+
+ +
+
+start_mixin_frame2ttl()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.HasBpod.html b/api/iblrig.base_tasks.HasBpod.html new file mode 100644 index 000000000..00daa572f --- /dev/null +++ b/api/iblrig.base_tasks.HasBpod.html @@ -0,0 +1,218 @@ + + + + + + + iblrig.base_tasks.HasBpod — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.HasBpod

+
Inheritance diagram of HasBpod
+ + + + +
+

+
+
+
+class iblrig.base_tasks.HasBpod[source]
+
+
+__init__(*args, **kwargs)
+
+ +
+
+bpod: Bpod
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.NetworkSession.html b/api/iblrig.base_tasks.NetworkSession.html new file mode 100644 index 000000000..56fa43f93 --- /dev/null +++ b/api/iblrig.base_tasks.NetworkSession.html @@ -0,0 +1,348 @@ + + + + + + + iblrig.base_tasks.NetworkSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.NetworkSession

+
Inheritance diagram of NetworkSession
+ + + + +
+

+
+
+
+class iblrig.base_tasks.NetworkSession[source]
+

A mixin for communicating to auxiliary acquisition PC over a network.

+
+
+__init__(*_, remote_rigs=None, **kwargs)[source]
+

A mixin for communicating to auxiliary acquisition PC over a network.

+

This should retrieve the services list, i.e. the list of available auxiliary rigs, +and determine which is the main sync. The main sync is the rig that determines the +experiment.

+

The services list is in a yaml file somewhere, called ‘remote_rigs.yaml’ and should +be a map of device name to URI. These are then selectable in the GUI and the URI of +those selected are added to the experiment description.

+

Subclasses should add their callbacks within init by calling self.remote_rigs.services.assign_callback().

+
+
Parameters:
+
    +
  • remote_rigs (list, dict) – Either a list of remote device names (in which case URI is looked up from remote devices +file), or a map of device name to URI.

  • +
  • kwargs – Optional args such as ‘file_iblrig_settings’ for defining location of remote data folder +when loading remote devices file.

  • +
+
+
+
+ +
+
+cleanup_mixin_network()[source]
+

Clean up services.

+
+ +
+
+communicate(message, *args, raise_on_exception=True)[source]
+

Communicate message to remote services.

+

This method is blocking and by default will raise if not all responses received in time.

+
+
Parameters:
+
    +
  • message (iblutil.io.net.base.ExpMessage, str, int) – An experiment message to send to remote services.

  • +
  • args – One or more optional variables to send.

  • +
  • raise_on_exception (bool) – If true, exceptions arising from message timeouts will be re-raised in main thread and +services will be cleaned up. Only applies when wait is true.

  • +
+
+
Returns:
+

If raise_on_exception is False, returns an exception if failed to receive all responses +in time, otherwise a map of service name to response is returned.

+
+
Return type:
+

Exception | dict

+
+
+
+ +
+
+connect(remote_rigs)[source]
+

Connect to remote services.

+

Instantiates the Communicator objects that establish connections with each remote device. +This also creates the thread that uses asynchronous callbacks.

+
+
Parameters:
+

remote_rigs (dict) – A map of name to URI.

+
+
+
+ +
+
+get_exp_info()[source]
+
+ +
+
+init_mixin_network()[source]
+

Initialize remote services.

+

This method sends an EXPINFO message to all services, expecting exactly one of the responses +to contain main_sync: True, along with the experiment reference to use. It then sends an +EXPINIT message to all services.

+
+ +
+
+run()[source]
+

Run session and report exceptions to remote services.

+
+ +
+
+start_mixin_network()[source]
+

Start remote services.

+

This method sends an EXPSTART message to all services, along with an exp_ref string. +Responses are required but ignored.

+
+ +
+
+stop_mixin_network()[source]
+

Start remote services.

+

This method sends an EXPEND message to all services. Responses are required but ignored.

+
+ +
+
+exp_ref = None
+

The experiment reference (i.e. subject, date, sequence) as returned by main remote service.

+
+
Type:
+

dict

+
+
+
+ +
+
+property one
+

Return ONE instance.

+

Unlike super class getter, this method will always instantiate ONE, allowing subclasses to update with an Alyx +token from a remotely connected rig. This instance is used for formatting the experiment reference string.

+
+
Returns:
+

An instance of ONE.

+
+
Return type:
+

one.api.One

+
+
+
+ +
+
+remote_rigs = None
+

An auxiliary services object for communicating with remote devices.

+
+
Type:
+

net.Auxiliaries

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.OSCClient.html b/api/iblrig.base_tasks.OSCClient.html new file mode 100644 index 000000000..fe2002f95 --- /dev/null +++ b/api/iblrig.base_tasks.OSCClient.html @@ -0,0 +1,244 @@ + + + + + + + iblrig.base_tasks.OSCClient — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.OSCClient

+
Inheritance diagram of OSCClient
+ + +
+

+
+
+
+class iblrig.base_tasks.OSCClient[source]
+

Handles communication to Bonsai using a UDP Client +OSC channels:

+
+

USED: +/t -> (int) trial number current +/p -> (int) position of stimulus init for current trial +/h -> (float) phase of gabor for current trial +/c -> (float) contrast of stimulus for current trial +/f -> (float) frequency of gabor patch for current trial +/a -> (float) angle of gabor patch for current trial +/g -> (float) gain of RE to visual stim displacement +/s -> (float) sigma of the 2D gaussian of gabor +/e -> (int) events transitions USED BY SOFTCODE HANDLER FUNC +/r -> (int) whether to reverse the side contingencies (0, 1)

+
+
+
+__init__(port, ip='127.0.0.1')[source]
+
+ +
+
+exit()[source]
+
+ +
+
+send2bonsai(**kwargs)[source]
+

:param see list of keys in OSC_PROTOCOL +:example: client.send2bonsai(trial_num=6, sim_freq=50) +:return:

+
+ +
+
+OSC_PROTOCOL = {'contrast': {'mess': '/c', 'type': <class 'float'>}, 'position': {'mess': '/p', 'type': <class 'int'>}, 'stim_angle': {'mess': '/a', 'type': <class 'float'>}, 'stim_freq': {'mess': '/f', 'type': <class 'float'>}, 'stim_gain': {'mess': '/g', 'type': <class 'float'>}, 'stim_phase': {'mess': '/h', 'type': <class 'float'>}, 'stim_sigma': {'mess': '/s', 'type': <class 'float'>}, 'trial_num': {'mess': '/t', 'type': <class 'int'>}}
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.RotaryEncoderMixin.html b/api/iblrig.base_tasks.RotaryEncoderMixin.html new file mode 100644 index 000000000..fa2065003 --- /dev/null +++ b/api/iblrig.base_tasks.RotaryEncoderMixin.html @@ -0,0 +1,219 @@ + + + + + + + iblrig.base_tasks.RotaryEncoderMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.RotaryEncoderMixin

+
Inheritance diagram of RotaryEncoderMixin
+ + + + +
+

+
+
+
+class iblrig.base_tasks.RotaryEncoderMixin[source]
+

Rotary encoder interface for state machine.

+
+
+init_mixin_rotary_encoder(*args, **kwargs)[source]
+
+ +
+
+start_mixin_rotary_encoder()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.SoundMixin.html b/api/iblrig.base_tasks.SoundMixin.html new file mode 100644 index 000000000..53241daa5 --- /dev/null +++ b/api/iblrig.base_tasks.SoundMixin.html @@ -0,0 +1,238 @@ + + + + + + + iblrig.base_tasks.SoundMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.SoundMixin

+
Inheritance diagram of SoundMixin
+ + + + + + + +
+

+
+
+
+class iblrig.base_tasks.SoundMixin[source]
+

Sound interface methods for state machine.

+
+
+init_mixin_sound()[source]
+
+ +
+
+sound_play_noise(state_timer=0.51, state_name='play_noise')[source]
+

Play the noise sound for the error feedback using bpod state machine. +:return: bpod current trial export

+
+ +
+
+sound_play_tone(state_timer=0.102, state_name='play_tone')[source]
+

Play the ready tone beep using bpod state machine. +:return: bpod current trial export

+
+ +
+
+start_mixin_sound()[source]
+

Depends on bpod mixin start for hard sound card +:return:

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.SpontaneousSession.html b/api/iblrig.base_tasks.SpontaneousSession.html new file mode 100644 index 000000000..47c96a463 --- /dev/null +++ b/api/iblrig.base_tasks.SpontaneousSession.html @@ -0,0 +1,220 @@ + + + + + + + iblrig.base_tasks.SpontaneousSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.SpontaneousSession

+
Inheritance diagram of SpontaneousSession
+ + + + +
+

+
+
+
+class iblrig.base_tasks.SpontaneousSession[source]
+

A Spontaneous task doesn’t have trials, it just runs until the user stops it.

+

It is used to get extraction structure for data streams

+
+
+__init__(duration_secs=None, **kwargs)[source]
+
+ +
+
+start_hardware()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.ValveMixin.html b/api/iblrig.base_tasks.ValveMixin.html new file mode 100644 index 000000000..4e84011a1 --- /dev/null +++ b/api/iblrig.base_tasks.ValveMixin.html @@ -0,0 +1,257 @@ + + + + + + + iblrig.base_tasks.ValveMixin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks.ValveMixin

+
Inheritance diagram of ValveMixin
+ + + + + + + +
+

+
+
+
+class iblrig.base_tasks.ValveMixin[source]
+
+
+compute_reward_time(amount_ul=None)[source]
+

Converts the valve opening time from a given volume.

+
+
Parameters:
+

amount_ul (float, optional) – The volume of liquid (μl) to be dispensed from the valve. Defaults to task_params.REWARD_AMOUNT_UL.

+
+
Returns:
+

Valve opening time in seconds.

+
+
Return type:
+

float

+
+
Parameters:
+

amount_ul (float | None)

+
+
+
+ +
+
+init_mixin_valve()[source]
+
+
Parameters:
+

self (object)

+
+
+
+ +
+
+start_mixin_valve()[source]
+
+ +
+
+valve_open(reward_valve_time)[source]
+

Open the reward valve for a given amount of time and return bpod data.

+
+
Parameters:
+

reward_valve_time (float) – Amount of time in seconds to open the reward valve.

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.base_tasks.html b/api/iblrig.base_tasks.html new file mode 100644 index 000000000..35607ce23 --- /dev/null +++ b/api/iblrig.base_tasks.html @@ -0,0 +1,241 @@ + + + + + + + iblrig.base_tasks — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.base_tasks

+

Commonalities for all tasks.

+

This module provides hardware mixins that can be used together with BaseSession to compose tasks. +This module tries to exclude task related logic.

+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

BaseSession

BonsaiRecordingMixin

BonsaiVisualStimulusMixin

BpodMixin

EmptySession

Frame2TTLMixin

Frame 2 TTL interface for state machine.

HasBpod

NetworkSession

A mixin for communicating to auxiliary acquisition PC over a network.

OSCClient

Handles communication to Bonsai using a UDP Client OSC channels: USED: /t -> (int) trial number current /p -> (int) position of stimulus init for current trial /h -> (float) phase of gabor for current trial /c -> (float) contrast of stimulus for current trial /f -> (float) frequency of gabor patch for current trial /a -> (float) angle of gabor patch for current trial /g -> (float) gain of RE to visual stim displacement /s -> (float) sigma of the 2D gaussian of gabor /e -> (int) events transitions USED BY SOFTCODE HANDLER FUNC /r -> (int) whether to reverse the side contingencies (0, 1)

RotaryEncoderMixin

Rotary encoder interface for state machine.

SoundMixin

Sound interface methods for state machine.

SpontaneousSession

A Spontaneous task doesn't have trials, it just runs until the user stops it.

ValveMixin

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.compute_adaptive_reward_volume.html b/api/iblrig.choiceworld.compute_adaptive_reward_volume.html new file mode 100644 index 000000000..d765e585a --- /dev/null +++ b/api/iblrig.choiceworld.compute_adaptive_reward_volume.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.choiceworld.compute_adaptive_reward_volume — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld.compute_adaptive_reward_volume

+
+
+iblrig.choiceworld.compute_adaptive_reward_volume(subject_weight_g, reward_volume_ul, delivered_volume_ul, ntrials)[source]
+

If the mouse completed over 200 trials in the previous session, the reward volume is automatically +lowered by 0.1 microliters for the next session, but cannot go lower than a floor of 1.5 microliters. +If the mouse received less than its minimum required daily dose (~1 milliliter/25 grams of body weight) +during the previous session, the reward volume is increased by 0.1 microliters for the next session,

+
+

but cannot go above a ceiling of 3 microliters.

+
+
+
Parameters:
+
    +
  • subject_weight_g – in grams

  • +
  • reward_volume_ul – the last reward volume setting in uL

  • +
  • delivered_volume_ul – the cumulative water deliverd during the last session in uL

  • +
  • n_trials

  • +
+
+
Returns:
+

adaptive_reward_ul

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.contrasts_set.html b/api/iblrig.choiceworld.contrasts_set.html new file mode 100644 index 000000000..d323d8836 --- /dev/null +++ b/api/iblrig.choiceworld.contrasts_set.html @@ -0,0 +1,201 @@ + + + + + + + iblrig.choiceworld.contrasts_set — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld.contrasts_set

+
+
+iblrig.choiceworld.contrasts_set(phase)[source]
+
+
Parameters:
+

phase (int)

+
+
Return type:
+

array

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.draw_training_contrast.html b/api/iblrig.choiceworld.draw_training_contrast.html new file mode 100644 index 000000000..abf5dcfef --- /dev/null +++ b/api/iblrig.choiceworld.draw_training_contrast.html @@ -0,0 +1,201 @@ + + + + + + + iblrig.choiceworld.draw_training_contrast — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld.draw_training_contrast

+
+
+iblrig.choiceworld.draw_training_contrast(phase)[source]
+
+
Parameters:
+

phase (int)

+
+
Return type:
+

float

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.get_subject_training_info.html b/api/iblrig.choiceworld.get_subject_training_info.html new file mode 100644 index 000000000..64fe53ad3 --- /dev/null +++ b/api/iblrig.choiceworld.get_subject_training_info.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.choiceworld.get_subject_training_info — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld.get_subject_training_info

+
+
+iblrig.choiceworld.get_subject_training_info(subject_name, task_name='_iblrig_tasks_trainingChoiceWorld', stim_gain=None, stim_gain_on_error=None, default_reward=3.0, mode='silent', **kwargs)[source]
+

Goes through a subject’s history and gets the latest training phase and adaptive reward volume.

+
+
Parameters:
+
    +
  • subject_name (str) – Name of the subject.

  • +
  • task_name (str, optional) – Name of the protocol to look for in experiment description, defaults to ‘_iblrig_tasks_trainingChoiceWorld’.

  • +
  • stim_gain (float, optional) – Default stimulus gain if no previous session is available, default to None

  • +
  • stim_gain_on_error (float, optional) – Default stimulus gain if there was an exception whilst obtaining the previous sessions’ info, default to None

  • +
  • default_reward (float, optional) – Default reward volume in uL if no previous session is available.

  • +
  • mode (str, optional) – If ‘silent’ returns default values if no history is found, if ‘raise’ raises ValueError.

  • +
  • **kwargs – Optional arguments to be passed to get_local_and_remote_paths

  • +
+
+
Returns:
+

    +
  • training_info (dict) – Dictionary with keys: training_phase, adaptive_reward, adaptive_gain

  • +
  • session_info (dict or None) – Dictionary with keys: session_path, experiment_description, task_settings, file_task_data

  • +
+

+
+
Parameters:
+
    +
  • subject_name (str)

  • +
  • task_name (str)

  • +
  • stim_gain (float | None)

  • +
  • stim_gain_on_error (float | None)

  • +
  • default_reward (float)

  • +
  • mode (Literal['silent', 'raise'])

  • +
+
+
Return type:
+

tuple[dict, dict | None]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.html b/api/iblrig.choiceworld.html new file mode 100644 index 000000000..9429f39a2 --- /dev/null +++ b/api/iblrig.choiceworld.html @@ -0,0 +1,212 @@ + + + + + + + iblrig.choiceworld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld

+

Choice World Task related logic and functions that translate the task description in +Appendix 2 of the paper into code.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + +

compute_adaptive_reward_volume

If the mouse completed over 200 trials in the previous session, the reward volume is automatically lowered by 0.1 microliters for the next session, but cannot go lower than a floor of 1.5 microliters. If the mouse received less than its minimum required daily dose (~1 milliliter/25 grams of body weight) during the previous session, the reward volume is increased by 0.1 microliters for the next session, but cannot go above a ceiling of 3 microliters. :param subject_weight_g: in grams :param reward_volume_ul: the last reward volume setting in uL :param delivered_volume_ul: the cumulative water deliverd during the last session in uL :param n_trials: :return: adaptive_reward_ul.

contrasts_set

draw_training_contrast

get_subject_training_info

Goes through a subject's history and gets the latest training phase and adaptive reward volume.

training_contrasts_probabilities

training_phase_from_contrast_set

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.training_contrasts_probabilities.html b/api/iblrig.choiceworld.training_contrasts_probabilities.html new file mode 100644 index 000000000..9d4aa6434 --- /dev/null +++ b/api/iblrig.choiceworld.training_contrasts_probabilities.html @@ -0,0 +1,193 @@ + + + + + + + iblrig.choiceworld.training_contrasts_probabilities — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld.training_contrasts_probabilities

+
+
+iblrig.choiceworld.training_contrasts_probabilities(phase=1)[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.choiceworld.training_phase_from_contrast_set.html b/api/iblrig.choiceworld.training_phase_from_contrast_set.html new file mode 100644 index 000000000..7b1f084ad --- /dev/null +++ b/api/iblrig.choiceworld.training_phase_from_contrast_set.html @@ -0,0 +1,201 @@ + + + + + + + iblrig.choiceworld.training_phase_from_contrast_set — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.choiceworld.training_phase_from_contrast_set

+
+
+iblrig.choiceworld.training_phase_from_contrast_set(contrast_set)[source]
+
+
Parameters:
+

contrast_set (list[float])

+
+
Return type:
+

int | None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.dir_path.html b/api/iblrig.commands.dir_path.html new file mode 100644 index 000000000..3eb1c6d60 --- /dev/null +++ b/api/iblrig.commands.dir_path.html @@ -0,0 +1,219 @@ + + + + + + + iblrig.commands.dir_path — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.dir_path

+
+
+iblrig.commands.dir_path(directory)[source]
+

Convert a string to a Path object and check if the directory exists.

+

This function is intended for use as a type conversion function with argparse. +It takes a string argument representing a directory path, converts it into +a Path object, and checks if the directory exists. If the directory exists, +it returns the Path object; otherwise, it raises an argparse.ArgumentError +with an appropriate error message.

+
+
Parameters:
+

directory (str) – A string representing a directory path.

+
+
Returns:
+

A Path object representing the directory.

+
+
Return type:
+

pathlib.Path

+
+
Raises:
+

argparse.ArgumentError – If the directory does not exist, an argparse.ArgumentError is raised + with an error message indicating that the directory was not found.

+
+
Parameters:
+

directory (str)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.flush.html b/api/iblrig.commands.flush.html new file mode 100644 index 000000000..9f898e0af --- /dev/null +++ b/api/iblrig.commands.flush.html @@ -0,0 +1,196 @@ + + + + + + + iblrig.commands.flush — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.flush

+
+
+iblrig.commands.flush()[source]
+

Flush the valve until the user hits enter.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.html b/api/iblrig.commands.html new file mode 100644 index 000000000..7f33a4383 --- /dev/null +++ b/api/iblrig.commands.html @@ -0,0 +1,218 @@ + + + + + + + iblrig.commands — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

dir_path

Convert a string to a Path object and check if the directory exists.

flush

Flush the valve until the user hits enter.

remove_local_sessions

Remove local sessions older than N weeks.

transfer_data

Copies data from the rig to the local server.

transfer_data_cli

Command-line interface for transferring behavioral data to the local server.

transfer_ephys_data_cli

Command-line interface for transferring ephys data to the local server.

transfer_video_data_cli

Command-line interface for transferring video data to the local server.

view_session

Entry point for command line: usage as below >>> view_session /full/path/to/jsonable/_iblrig_taskData.raw.jsonable :return: None

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.remove_local_sessions.html b/api/iblrig.commands.remove_local_sessions.html new file mode 100644 index 000000000..195e235f2 --- /dev/null +++ b/api/iblrig.commands.remove_local_sessions.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.commands.remove_local_sessions — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.remove_local_sessions

+
+
+iblrig.commands.remove_local_sessions(weeks=2, local_path=None, remote_path=None, dry=False, tag='behavior')[source]
+

Remove local sessions older than N weeks.

+
+
Parameters:
+
    +
  • weeks (int) – Remove local sessions older than this number of weeks.

  • +
  • local_path (Path) – Path to local subjects folder, otherwise fetches path from iblrig_settings.yaml file.

  • +
  • remote_path (Path) – Path to remote subjects folder, otherwise fetches path from iblrig_settings.yaml file.

  • +
  • dry (bool) – Do not remove local data if True.

  • +
  • tag (str) – The acquisition PC tag to transfer, e.g. ‘behavior’, ‘video’, ‘ephys’, ‘timeline’, etc.

  • +
+
+
Returns:
+

A list of removed session paths.

+
+
Return type:
+

list of Path

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.transfer_data.html b/api/iblrig.commands.transfer_data.html new file mode 100644 index 000000000..caeba13b6 --- /dev/null +++ b/api/iblrig.commands.transfer_data.html @@ -0,0 +1,223 @@ + + + + + + + iblrig.commands.transfer_data — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.transfer_data

+
+
+iblrig.commands.transfer_data(tag=None, local_path=None, remote_path=None, dry=False, interactive=False, cleanup_weeks=2, **kwargs)[source]
+

Copies data from the rig to the local server.

+
+
Parameters:
+
    +
  • tag (str) – The acquisition PC tag to transfer, e.g. ‘behavior’, ‘video’, ‘ephys’, ‘timeline’, etc.

  • +
  • local_path (Path) – Path to local subjects folder, otherwise fetches path from iblrig_settings.yaml file.

  • +
  • remote_path (Path) – Path to remote subjects folder, otherwise fetches path from iblrig_settings.yaml file.

  • +
  • dry (bool) – Do not copy or remove local data.

  • +
  • interactive (bool) – If true, users are prompted to review the sessions to copy before proceeding.

  • +
  • cleanup_weeks (int, bool) – Remove local data older than this number of weeks. If False, do not remove.

  • +
  • kwargs – Optional arguments to pass to SessionCopier constructor.

  • +
+
+
Returns:
+

A list of the copier objects that were run.

+
+
Return type:
+

list of SessionCopier

+
+
Parameters:
+
    +
  • local_path (Path | None)

  • +
  • remote_path (Path | None)

  • +
  • dry (bool)

  • +
  • interactive (bool)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.transfer_data_cli.html b/api/iblrig.commands.transfer_data_cli.html new file mode 100644 index 000000000..d12afa7bb --- /dev/null +++ b/api/iblrig.commands.transfer_data_cli.html @@ -0,0 +1,196 @@ + + + + + + + iblrig.commands.transfer_data_cli — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.transfer_data_cli

+
+
+iblrig.commands.transfer_data_cli()[source]
+

Command-line interface for transferring behavioral data to the local server.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.transfer_ephys_data_cli.html b/api/iblrig.commands.transfer_ephys_data_cli.html new file mode 100644 index 000000000..76035f049 --- /dev/null +++ b/api/iblrig.commands.transfer_ephys_data_cli.html @@ -0,0 +1,196 @@ + + + + + + + iblrig.commands.transfer_ephys_data_cli — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.transfer_ephys_data_cli

+
+
+iblrig.commands.transfer_ephys_data_cli()[source]
+

Command-line interface for transferring ephys data to the local server.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.transfer_video_data_cli.html b/api/iblrig.commands.transfer_video_data_cli.html new file mode 100644 index 000000000..4f0653a59 --- /dev/null +++ b/api/iblrig.commands.transfer_video_data_cli.html @@ -0,0 +1,196 @@ + + + + + + + iblrig.commands.transfer_video_data_cli — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.transfer_video_data_cli

+
+
+iblrig.commands.transfer_video_data_cli()[source]
+

Command-line interface for transferring video data to the local server.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.commands.view_session.html b/api/iblrig.commands.view_session.html new file mode 100644 index 000000000..6e1df28ed --- /dev/null +++ b/api/iblrig.commands.view_session.html @@ -0,0 +1,198 @@ + + + + + + + iblrig.commands.view_session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.commands.view_session

+
+
+iblrig.commands.view_session()[source]
+

Entry point for command line: usage as below +>>> view_session /full/path/to/jsonable/_iblrig_taskData.raw.jsonable +:return: None

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.constants.html b/api/iblrig.constants.html new file mode 100644 index 000000000..6fe97b246 --- /dev/null +++ b/api/iblrig.constants.html @@ -0,0 +1,179 @@ + + + + + + + iblrig.constants — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.ephys.html b/api/iblrig.ephys.html new file mode 100644 index 000000000..1754b7e33 --- /dev/null +++ b/api/iblrig.ephys.html @@ -0,0 +1,198 @@ + + + + + + + iblrig.ephys — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.ephys

+

Functions

+ + + + + + + + + + + + +

neuropixel24_micromanipulator_coordinates

Provide the micro-manipulator coordinates of the first shank.

prepare_ephys_session

Setup electrophysiology recordings.

prepare_ephys_session_cmd

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.html b/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.html new file mode 100644 index 000000000..f1b16a082 --- /dev/null +++ b/api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.html @@ -0,0 +1,202 @@ + + + + + + + iblrig.ephys.neuropixel24_micromanipulator_coordinates — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.ephys.neuropixel24_micromanipulator_coordinates

+
+
+iblrig.ephys.neuropixel24_micromanipulator_coordinates(ref_shank, pname, ba=None, shank_spacings_um=(0, 200, 400, 600))[source]
+

Provide the micro-manipulator coordinates of the first shank.

+

This function returns the relative coordinates of all shanks, labeled as probe01a, probe01b, etc.

+
+
Parameters:
+

ref_shank – dictionary with keys x, y, z, phi, theta, depth, roll

+
+
+

example: {‘x’: 2594.2, ‘y’: -3123.7, ‘z’: -711, ‘phi’: 0 + 15, ‘theta’: 15, ‘depth’: 1250.4, ‘roll’: 0} +:param pname: str +:param ba: brain atlas object +:param shank_spacings_um: list of shank spacings in micrometers +:return:

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.ephys.prepare_ephys_session.html b/api/iblrig.ephys.prepare_ephys_session.html new file mode 100644 index 000000000..2b85d1da5 --- /dev/null +++ b/api/iblrig.ephys.prepare_ephys_session.html @@ -0,0 +1,205 @@ + + + + + + + iblrig.ephys.prepare_ephys_session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.ephys.prepare_ephys_session

+
+
+iblrig.ephys.prepare_ephys_session(subject_name, nprobes=2)[source]
+

Setup electrophysiology recordings.

+
+
Parameters:
+
    +
  • subject_name (str) – A subject name.

  • +
  • nprobes (int) – Number of probes to be used

  • +
+
+
Parameters:
+
    +
  • subject_name (str)

  • +
  • nprobes (int)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.ephys.prepare_ephys_session_cmd.html b/api/iblrig.ephys.prepare_ephys_session_cmd.html new file mode 100644 index 000000000..a76ef8c38 --- /dev/null +++ b/api/iblrig.ephys.prepare_ephys_session_cmd.html @@ -0,0 +1,190 @@ + + + + + + + iblrig.ephys.prepare_ephys_session_cmd — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.frame2ttl.Frame2TTL.html b/api/iblrig.frame2ttl.Frame2TTL.html new file mode 100644 index 000000000..bea682af3 --- /dev/null +++ b/api/iblrig.frame2ttl.Frame2TTL.html @@ -0,0 +1,284 @@ + + + + + + + iblrig.frame2ttl.Frame2TTL — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.frame2ttl.Frame2TTL

+
Inheritance diagram of Frame2TTL
+ + + + + +
+

+
+
+
+class iblrig.frame2ttl.Frame2TTL[source]
+
+
+__init__(port, threshold_light=None, threshold_dark=None, **kwargs)[source]
+
+
Parameters:
+
    +
  • port (str)

  • +
  • threshold_light (int | None)

  • +
  • threshold_dark (int | None)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+calibrate(condition, n_samples=1000)[source]
+
+
Parameters:
+
    +
  • condition (Literal['light', 'dark'])

  • +
  • n_samples (int)

  • +
+
+
Return type:
+

tuple[int, bool]

+
+
+
+ +
+
+handshake(raise_on_fail=False)[source]
+
+
Parameters:
+

raise_on_fail (bool)

+
+
Return type:
+

bool

+
+
+
+ +
+
+sample(n_samples)[source]
+
+
Parameters:
+

n_samples (int)

+
+
Return type:
+

ndarray

+
+
+
+ +
+
+set_thresholds(light, dark)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+property streaming: bool
+
+ +
+
+property threshold_dark: int
+
+ +
+
+property threshold_light: int
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.frame2ttl.html b/api/iblrig.frame2ttl.html new file mode 100644 index 000000000..5aad40db4 --- /dev/null +++ b/api/iblrig.frame2ttl.html @@ -0,0 +1,190 @@ + + + + + + + iblrig.frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.graphic.html b/api/iblrig.graphic.html new file mode 100644 index 000000000..89506b7ce --- /dev/null +++ b/api/iblrig.graphic.html @@ -0,0 +1,191 @@ + + + + + + + iblrig.graphic — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.graphic.numinput.html b/api/iblrig.graphic.numinput.html new file mode 100644 index 000000000..042ad69e8 --- /dev/null +++ b/api/iblrig.graphic.numinput.html @@ -0,0 +1,188 @@ + + + + + + + iblrig.graphic.numinput — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.html b/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.html new file mode 100644 index 000000000..a5049892b --- /dev/null +++ b/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.html @@ -0,0 +1,231 @@ + + + + + + + iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog

+
Inheritance diagram of Frame2TTLCalibrationDialog
+ + + +
+

+
+
+
+class iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog[source]
+
+
+__init__(*args, hardware_settings, **kwargs)[source]
+
+
Parameters:
+

hardware_settings (HardwareSettings)

+
+
Return type:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.html b/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.html new file mode 100644 index 000000000..9c37a36e3 --- /dev/null +++ b/api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.html @@ -0,0 +1,242 @@ + + + + + + + iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget

+
Inheritance diagram of Frame2TTLCalibrationTarget
+ + +
+

+
+
+
+class iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget[source]
+
+
+__init__(parent=None, color=<PyQt5.QtGui.QColor object>, screen_index=None, width=None, height=None, rel_pos_x=1.33, rel_pos_y=-1.03, rel_extent_x=0.2, rel_extent_y=0.2, **kwargs)[source]
+
+
Parameters:
+
    +
  • parent (QWidget | None)

  • +
  • color (QColor)

  • +
  • screen_index (int | None)

  • +
  • width (int | None)

  • +
  • height (int | None)

  • +
  • rel_pos_x (float)

  • +
  • rel_pos_y (float)

  • +
  • rel_extent_x (float)

  • +
  • rel_extent_y (float)

  • +
+
+
+
+ +
+
+property color: QColor
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.frame2ttl.html b/api/iblrig.gui.frame2ttl.html new file mode 100644 index 000000000..8a869993e --- /dev/null +++ b/api/iblrig.gui.frame2ttl.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.gui.frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.frame2ttl

+

Classes

+ + + + + + + + + +

Frame2TTLCalibrationDialog

Frame2TTLCalibrationTarget

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.html b/api/iblrig.gui.html new file mode 100644 index 000000000..be497c7d7 --- /dev/null +++ b/api/iblrig.gui.html @@ -0,0 +1,278 @@ + + + + + + + iblrig.gui — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui

+

Modules

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

frame2ttl

resources_rc

splash

tab_about

tab_data

tab_docs

tab_log

tools

ui_frame2ttl

ui_login

ui_splash

ui_tab_about

ui_tab_data

ui_tab_docs

ui_tab_log

ui_tab_session

ui_update

ui_validation

ui_valve

ui_wizard

validation

valve

wizard

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.resources_rc.html b/api/iblrig.gui.resources_rc.html new file mode 100644 index 000000000..7481ba245 --- /dev/null +++ b/api/iblrig.gui.resources_rc.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.gui.resources_rc — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.resources_rc

+

Functions

+ + + + + + + + + +

qCleanupResources

qInitResources

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.resources_rc.qCleanupResources.html b/api/iblrig.gui.resources_rc.qCleanupResources.html new file mode 100644 index 000000000..d96c023c8 --- /dev/null +++ b/api/iblrig.gui.resources_rc.qCleanupResources.html @@ -0,0 +1,211 @@ + + + + + + + iblrig.gui.resources_rc.qCleanupResources — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.resources_rc.qCleanupResources

+
+
+iblrig.gui.resources_rc.qCleanupResources()[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.resources_rc.qInitResources.html b/api/iblrig.gui.resources_rc.qInitResources.html new file mode 100644 index 000000000..25f8485b6 --- /dev/null +++ b/api/iblrig.gui.resources_rc.qInitResources.html @@ -0,0 +1,211 @@ + + + + + + + iblrig.gui.resources_rc.qInitResources — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.resources_rc.qInitResources

+
+
+iblrig.gui.resources_rc.qInitResources()[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.splash.Splash.html b/api/iblrig.gui.splash.Splash.html new file mode 100644 index 000000000..13608189f --- /dev/null +++ b/api/iblrig.gui.splash.Splash.html @@ -0,0 +1,249 @@ + + + + + + + iblrig.gui.splash.Splash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.splash.Splash

+
Inheritance diagram of Splash
+ + + +
+

+
+
+
+class iblrig.gui.splash.Splash[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+close()[source]
+
+ +
+
+eventFilter(obj, event)[source]
+

Disregard all key-presses.

+
+ +
+
+stop_and_close()[source]
+
+ +
+
+validation()[source]
+
+ +
+
+validation_results: list[Result] = []
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.splash.html b/api/iblrig.gui.splash.html new file mode 100644 index 000000000..3cd80cd33 --- /dev/null +++ b/api/iblrig.gui.splash.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.splash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.splash

+

Classes

+ + + + + + +

Splash

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_about.TabAbout.html b/api/iblrig.gui.tab_about.TabAbout.html new file mode 100644 index 000000000..60b686f40 --- /dev/null +++ b/api/iblrig.gui.tab_about.TabAbout.html @@ -0,0 +1,236 @@ + + + + + + + iblrig.gui.tab_about.TabAbout — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_about.TabAbout

+
Inheritance diagram of TabAbout
+ + + +
+

+
+
+
+class iblrig.gui.tab_about.TabAbout[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+onGetAnydeskResult(result)[source]
+
+
Parameters:
+

result (str | None)

+
+
Return type:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_about.html b/api/iblrig.gui.tab_about.html new file mode 100644 index 000000000..a54e77547 --- /dev/null +++ b/api/iblrig.gui.tab_about.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.tab_about — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_about

+

Classes

+ + + + + + +

TabAbout

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_data.Column.html b/api/iblrig.gui.tab_data.Column.html new file mode 100644 index 000000000..fc28c38ec --- /dev/null +++ b/api/iblrig.gui.tab_data.Column.html @@ -0,0 +1,258 @@ + + + + + + + iblrig.gui.tab_data.Column — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_data.Column

+
Inheritance diagram of Column
+ + +
+

+
+
+
+class iblrig.gui.tab_data.Column[source]
+

Column(name, hidden, resizeMode, sectionWidth)

+
+
+static __new__(_cls, name, hidden=False, resizeMode=2, sectionWidth=130)
+

Create new instance of Column(name, hidden, resizeMode, sectionWidth)

+
+
Parameters:
+
    +
  • name (str)

  • +
  • hidden (bool)

  • +
  • resizeMode (ResizeMode)

  • +
  • sectionWidth (int)

  • +
+
+
+
+ +
+
+hidden: bool
+

Alias for field number 1

+
+ +
+
+name: str
+

Alias for field number 0

+
+ +
+
+resizeMode: ResizeMode
+

Alias for field number 2

+
+ +
+
+sectionWidth: int
+

Alias for field number 3

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_data.DataItemDelegate.html b/api/iblrig.gui.tab_data.DataItemDelegate.html new file mode 100644 index 000000000..a04f8a688 --- /dev/null +++ b/api/iblrig.gui.tab_data.DataItemDelegate.html @@ -0,0 +1,222 @@ + + + + + + + iblrig.gui.tab_data.DataItemDelegate — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_data.DataItemDelegate

+
Inheritance diagram of DataItemDelegate
+ + +
+

+
+
+
+class iblrig.gui.tab_data.DataItemDelegate[source]
+
+
+initStyleOption(option, index)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_data.DataWorker.html b/api/iblrig.gui.tab_data.DataWorker.html new file mode 100644 index 000000000..600096778 --- /dev/null +++ b/api/iblrig.gui.tab_data.DataWorker.html @@ -0,0 +1,297 @@ + + + + + + + iblrig.gui.tab_data.DataWorker — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_data.DataWorker

+
Inheritance diagram of DataWorker
+ + +
+

+
+
+
+class iblrig.gui.tab_data.DataWorker[source]
+
+
+__init__(parent)[source]
+
+
Parameters:
+

parent (TabData)

+
+
+
+ +
+
+lazyLoadStatus()[source]
+
+ +
+
+run()[source]
+
+ +
+
+initialized
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+lazyLoadComplete
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+update
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_data.TabData.html b/api/iblrig.gui.tab_data.TabData.html new file mode 100644 index 000000000..0ac747b1d --- /dev/null +++ b/api/iblrig.gui.tab_data.TabData.html @@ -0,0 +1,228 @@ + + + + + + + iblrig.gui.tab_data.TabData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_data.TabData

+
Inheritance diagram of TabData
+ + + +
+

+
+
+
+class iblrig.gui.tab_data.TabData[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+showEvent(a0)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_data.html b/api/iblrig.gui.tab_data.html new file mode 100644 index 000000000..ab93d2817 --- /dev/null +++ b/api/iblrig.gui.tab_data.html @@ -0,0 +1,230 @@ + + + + + + + iblrig.gui.tab_data — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_data

+

Functions

+ + + + + + +

sizeof_fmt

+

Classes

+ + + + + + + + + + + + + + + +

Column

Column(name, hidden, resizeMode, sectionWidth)

DataItemDelegate

DataWorker

TabData

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_data.sizeof_fmt.html b/api/iblrig.gui.tab_data.sizeof_fmt.html new file mode 100644 index 000000000..366fd4313 --- /dev/null +++ b/api/iblrig.gui.tab_data.sizeof_fmt.html @@ -0,0 +1,211 @@ + + + + + + + iblrig.gui.tab_data.sizeof_fmt — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_data.sizeof_fmt

+
+
+iblrig.gui.tab_data.sizeof_fmt(num, suffix='B')[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_docs.CustomWebEnginePage.html b/api/iblrig.gui.tab_docs.CustomWebEnginePage.html new file mode 100644 index 000000000..6cd5124c9 --- /dev/null +++ b/api/iblrig.gui.tab_docs.CustomWebEnginePage.html @@ -0,0 +1,251 @@ + + + + + + + iblrig.gui.tab_docs.CustomWebEnginePage — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_docs.CustomWebEnginePage

+
Inheritance diagram of CustomWebEnginePage
+ + +
+

+
+
+
+class iblrig.gui.tab_docs.CustomWebEnginePage[source]
+

Custom implementation of QWebEnginePage to handle navigation requests.

+

This class overrides the acceptNavigationRequest method to handle link clicks. +If the navigation type is a link click and the clicked URL does not start with +a specific prefix (URL_DOC), it opens the URL in the default web browser. +Otherwise, it delegates the handling to the base class.

+

Adapted from: https://www.pythonguis.com/faq/qwebengineview-open-links-new-window/

+
+
+acceptNavigationRequest(url, navigationType, is_main_frame)[source]
+

Decide whether to allow or block a navigation request.

+
+
Parameters:
+
    +
  • url (QUrl) – The URL being navigated to.

  • +
  • navigationType (QWebEnginePage.NavigationType) – The type of navigation request.

  • +
  • is_main_frame (bool) – Indicates whether the request is for the main frame.

  • +
+
+
Returns:
+

True if the navigation request is accepted, False otherwise.

+
+
Return type:
+

bool

+
+
Parameters:
+
    +
  • url (QUrl)

  • +
  • navigationType (NavigationType)

  • +
  • is_main_frame (bool)

  • +
+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_docs.TabDocs.html b/api/iblrig.gui.tab_docs.TabDocs.html new file mode 100644 index 000000000..261e8f7b5 --- /dev/null +++ b/api/iblrig.gui.tab_docs.TabDocs.html @@ -0,0 +1,223 @@ + + + + + + + iblrig.gui.tab_docs.TabDocs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_docs.TabDocs

+
Inheritance diagram of TabDocs
+ + + +
+

+
+
+
+class iblrig.gui.tab_docs.TabDocs[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_docs.html b/api/iblrig.gui.tab_docs.html new file mode 100644 index 000000000..145b6885b --- /dev/null +++ b/api/iblrig.gui.tab_docs.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.gui.tab_docs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_docs

+

Classes

+ + + + + + + + + +

CustomWebEnginePage

Custom implementation of QWebEnginePage to handle navigation requests.

TabDocs

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_log.TabLog.html b/api/iblrig.gui.tab_log.TabLog.html new file mode 100644 index 000000000..0a9062ea3 --- /dev/null +++ b/api/iblrig.gui.tab_log.TabLog.html @@ -0,0 +1,286 @@ + + + + + + + iblrig.gui.tab_log.TabLog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_log.TabLog

+
Inheritance diagram of TabLog
+ + + +
+

+
+
+
+class iblrig.gui.tab_log.TabLog[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+appendText(text, color='White')[source]
+

Append text to the log.

+
+
Parameters:
+
    +
  • text (str) – The text to append.

  • +
  • color (str, optional) – The color of the text. Should be a valid color name recognized by +QtGui.QColorConstants. Defaults to ‘White’.

  • +
+
+
Parameters:
+
+
+
+
+ +
+
+clear()[source]
+

Clear the log.

+
+ +
+
+copyToClipboard()[source]
+

Copy the log contents to the clipboard as a markdown code-block.

+
+ +
+
+setFontSize(fontSize)[source]
+

Set the font size of the log-widget’s contents.

+
+
Parameters:
+

fontSize (int) – Font size of the log-widget’s contents in points.

+
+
Parameters:
+

fontSize (int)

+
+
+
+ +
+
+setLogColor(colorName)[source]
+

Set the foreground color of characters in the log widget.

+
+
Parameters:
+

colorName (str, optional) – The name of the color to set. Default is ‘White’. Should be a valid color name +recognized by QtGui.QColorConstants. If the provided color name is not found, +it defaults to QtGui.QColorConstants.White.

+
+
Parameters:
+

colorName (str)

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tab_log.html b/api/iblrig.gui.tab_log.html new file mode 100644 index 000000000..f54b4ab69 --- /dev/null +++ b/api/iblrig.gui.tab_log.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.tab_log — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tab_log

+

Classes

+ + + + + + +

TabLog

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.AlyxObject.html b/api/iblrig.gui.tools.AlyxObject.html new file mode 100644 index 000000000..de3bf5de6 --- /dev/null +++ b/api/iblrig.gui.tools.AlyxObject.html @@ -0,0 +1,448 @@ + + + + + + + iblrig.gui.tools.AlyxObject — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.AlyxObject

+
Inheritance diagram of AlyxObject
+ + +
+

+
+
+
+class iblrig.gui.tools.AlyxObject[source]
+

A class to manage user authentication with an AlyxClient.

+

This class provides methods to log in and log out users, emitting signals to indicate changes in authentication status.

+
+
Parameters:
+
    +
  • alyxUrl (str, optional) – The base URL for the Alyx API. If provided, an AlyxClient will be created.

  • +
  • alyxClient (AlyxClient, optional) – An existing AlyxClient instance. If provided, it will be used for authentication.

  • +
+
+
+
+
+isLoggedIn
+

Indicates whether a user is currently logged in.

+
+
Type:
+

bool

+
+
+
+ +
+
+username
+

The username of the logged-in user, or None if not logged in.

+
+
Type:
+

str or None

+
+
+
+ +
+
+statusChanged
+

Emitted when the login status changes (logged in or out). The signal carries a boolean indicating the new status.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+loggedIn
+

Emitted when a user logs in. The signal carries a string representing the username.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+loggedOut
+

Emitted when a user logs out. The signal carries a string representing the username.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+loginFailed
+

Emitted when a login attempt fails. The signal carries a string representing the username.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+__init__(*args, alyxUrl=None, alyxClient=None, **kwargs)[source]
+

Initializes the AlyxObject.

+
+
Parameters:
+
    +
  • *args (tuple) – Positional arguments for QObject.

  • +
  • alyxUrl (str, optional) – The base URL for the Alyx API.

  • +
  • alyxClient (AlyxClient, optional) – An existing AlyxClient instance.

  • +
  • **kwargs (dict) – Keyword arguments for QObject.

  • +
+
+
Parameters:
+
+
+
+
+ +
+
+logIn(username, password=None, cacheToken=False)[source]
+

Logs in a user with the provided username and password.

+

Emits the loggedIn and statusChanged signals if the logout is successful, and the loginFailed signal otherwise.

+
+
Parameters:
+
    +
  • username (str) – The username of the user attempting to log in.

  • +
  • password (str or None, optional) – The password of the user. If None, the login will proceed without a password.

  • +
  • cacheToken (bool, optional) – Whether to cache the authentication token.

  • +
+
+
Returns:
+

True if the login was successful, False otherwise.

+
+
Return type:
+

bool

+
+
Parameters:
+
    +
  • username (str)

  • +
  • password (str | None)

  • +
  • cacheToken (bool)

  • +
+
+
+
+ +
+
+logOut()[source]
+

Logs out the currently logged-in user.

+

Emits the loggedOut and statusChanged signals if the logout is successful.

+
+
Return type:
+

None

+
+
+
+ +
+
+property isLoggedIn
+

Indicates whether a user is currently logged in.

+
+ +
+
+loggedIn
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+loggedOut
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+loginFailed
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+statusChanged
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+property username: str | None
+

The username of the logged-in user, or None if not logged in.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.DataFrameTableModel.html b/api/iblrig.gui.tools.DataFrameTableModel.html new file mode 100644 index 000000000..eaef1ed50 --- /dev/null +++ b/api/iblrig.gui.tools.DataFrameTableModel.html @@ -0,0 +1,368 @@ + + + + + + + iblrig.gui.tools.DataFrameTableModel — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.DataFrameTableModel

+
Inheritance diagram of DataFrameTableModel
+ + +
+

+
+
+
+class iblrig.gui.tools.DataFrameTableModel[source]
+
+
+__init__(*args, df, **kwargs)[source]
+
+
Parameters:
+

df (DataFrame)

+
+
+
+ +
+
+columnCount(parent=Ellipsis)[source]
+

Get the number of columns in the model.

+
+
Parameters:
+

parent (QModelIndex, optional) – The parent index.

+
+
Returns:
+

The number of columns.

+
+
Return type:
+

int

+
+
+
+ +
+
+data(index, role=Ellipsis)[source]
+

Get the data for the specified index.

+
+
Parameters:
+
    +
  • index (QModelIndex) – The index of the data.

  • +
  • role (int, optional) – The role of the data.

  • +
+
+
Returns:
+

The data for the specified index.

+
+
Return type:
+

QVariant

+
+
+
+ +
+
+headerData(section, orientation, role=Ellipsis)[source]
+

Get the header data for the specified section.

+
+
Parameters:
+
    +
  • section (int) – The section index.

  • +
  • orientation (Qt.Orientation) – The orientation of the header.

  • +
  • role (int, optional) – The role of the header data.

  • +
+
+
Returns:
+

The header data.

+
+
Return type:
+

QVariant

+
+
+
+ +
+
+rowCount(parent=Ellipsis)[source]
+

Get the number of rows in the model.

+
+
Parameters:
+

parent (QModelIndex, optional) – The parent index.

+
+
Returns:
+

The number of rows.

+
+
Return type:
+

int

+
+
+
+ +
+
+setData(index, value, role=0)[source]
+

Set data at the specified index with the given value.

+
+
Parameters:
+
    +
  • index (QModelIndex) – The index where the data will be set.

  • +
  • value (Any) – The new value to be set at the specified index.

  • +
  • role (int, optional) – The role of the data. Default is Qt.DisplayRole.

  • +
+
+
+
+ +
+
+setDataFrame(data_frame)[source]
+
+
Parameters:
+

data_frame (DataFrame)

+
+
+
+ +
+
+sort(column, order=Ellipsis)[source]
+

Sort the data based on the specified column and order.

+
+
Parameters:
+
    +
  • column (int) – The column index to sort by.

  • +
  • order (Qt.SortOrder, optional) – The sort order.

  • +
+
+
+
+ +
+
+dataFrame
+
+
pyqtProperty(type, fget=None, fset=None, freset=None, fdel=None, doc=None,

designable=True, scriptable=True, stored=True, user=False, +constant=False, final=False, notify=None, +revision=0) -> property attribute

+
+
+

type is the type of the property. It is either a type object or a string +that is the name of a C++ type. +freset is a function for resetting an attribute to its default value. +designable sets the DESIGNABLE flag (the default is True for writable +properties and False otherwise). +scriptable sets the SCRIPTABLE flag. +stored sets the STORED flag. +user sets the USER flag. +constant sets the CONSTANT flag. +final sets the FINAL flag. +notify is the NOTIFY signal. +revision is the REVISION. +The other parameters are the same as those required by the standard Python +property type. Properties defined using pyqtProperty behave as both Python +and Qt properties. +Decorators can be used to define new properties or to modify existing ones.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.DiskSpaceIndicator.html b/api/iblrig.gui.tools.DiskSpaceIndicator.html new file mode 100644 index 000000000..ca3212795 --- /dev/null +++ b/api/iblrig.gui.tools.DiskSpaceIndicator.html @@ -0,0 +1,252 @@ + + + + + + + iblrig.gui.tools.DiskSpaceIndicator — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.DiskSpaceIndicator

+
Inheritance diagram of DiskSpaceIndicator
+ + +
+

+
+
+
+class iblrig.gui.tools.DiskSpaceIndicator[source]
+

A custom progress bar widget that indicates the disk space usage of a specified directory.

+
+
+__init__(*args, directory, percent_threshold=90, **kwargs)[source]
+

Initialize the DiskSpaceIndicator with the specified directory and threshold percentage.

+
+
Parameters:
+
    +
  • *args (tuple) – Variable length argument list (passed to QProgressBar).

  • +
  • directory (Path or None) – The directory path to monitor for disk space usage.

  • +
  • percent_threshold (int, optional) – The threshold percentage at which the progress bar changes color to red. Default is 90.

  • +
  • **kwargs (dict) – Arbitrary keyword arguments (passed to QProgressBar).

  • +
+
+
Parameters:
+
    +
  • directory (Path | None)

  • +
  • percent_threshold (int)

  • +
+
+
+
+ +
+
+update_data()[source]
+

Update the disk space information.

+
+ +
+
+property critical: bool
+

True if the disk space usage is above the given threshold percentage.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.LineEditAlyxUser.html b/api/iblrig.gui.tools.LineEditAlyxUser.html new file mode 100644 index 000000000..f6b8968f0 --- /dev/null +++ b/api/iblrig.gui.tools.LineEditAlyxUser.html @@ -0,0 +1,255 @@ + + + + + + + iblrig.gui.tools.LineEditAlyxUser — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.LineEditAlyxUser

+
Inheritance diagram of LineEditAlyxUser
+ + +
+

+
+
+
+class iblrig.gui.tools.LineEditAlyxUser[source]
+

A custom QLineEdit widget for managing user login with an AlyxObject.

+

This widget displays a checkmark icon to indicate the connection status +and allows the user to input their username for logging in.

+
+
Parameters:
+
    +
  • *args (tuple) – Positional arguments passed to the QLineEdit constructor.

  • +
  • alyx (AlyxObject) – An instance of AlyxObject used to manage login and connection status.

  • +
  • **kwargs (dict) – Keyword arguments passed to the QLineEdit constructor.

  • +
+
+
+
+
+__init__(*args, alyx, **kwargs)[source]
+

Initializes the LineEditAlyxUser widget.

+

Sets up the checkmark icon, connects signals for login status, +and configures the line edit based on the AlyxObject’s state.

+
+
Parameters:
+
    +
  • *args (tuple) – Positional arguments passed to the QLineEdit constructor.

  • +
  • alyx (AlyxObject) – An instance of AlyxObject.

  • +
  • **kwargs (dict) – Keyword arguments passed to the QLineEdit constructor.

  • +
+
+
Parameters:
+

alyx (AlyxObject)

+
+
+
+ +
+
+logIn()[source]
+

Attempt to log in using the line edit’s current text.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.RemoteDevicesItemModel.html b/api/iblrig.gui.tools.RemoteDevicesItemModel.html new file mode 100644 index 000000000..2e00922b8 --- /dev/null +++ b/api/iblrig.gui.tools.RemoteDevicesItemModel.html @@ -0,0 +1,232 @@ + + + + + + + iblrig.gui.tools.RemoteDevicesItemModel — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.RemoteDevicesItemModel

+
Inheritance diagram of RemoteDevicesItemModel
+ + +
+

+
+
+
+class iblrig.gui.tools.RemoteDevicesItemModel[source]
+
+
+__init__(*args, iblrig_settings, **kwargs)[source]
+
+
Parameters:
+

iblrig_settings (RigSettings)

+
+
+
+ +
+
+update()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.RemoteDevicesListView.html b/api/iblrig.gui.tools.RemoteDevicesListView.html new file mode 100644 index 000000000..caea57f14 --- /dev/null +++ b/api/iblrig.gui.tools.RemoteDevicesListView.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.tools.RemoteDevicesListView — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.RemoteDevicesListView

+
Inheritance diagram of RemoteDevicesListView
+ + +
+

+
+
+
+class iblrig.gui.tools.RemoteDevicesListView[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+getDevices()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.StatefulButton.html b/api/iblrig.gui.tools.StatefulButton.html new file mode 100644 index 000000000..e5341c885 --- /dev/null +++ b/api/iblrig.gui.tools.StatefulButton.html @@ -0,0 +1,377 @@ + + + + + + + iblrig.gui.tools.StatefulButton — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.StatefulButton

+
Inheritance diagram of StatefulButton
+ + +
+

+
+
+
+class iblrig.gui.tools.StatefulButton[source]
+

A QPushButton that maintains an active/inactive state and emits different signals +based on its state when clicked.

+
+
Parameters:
+

active (bool, optional) – Initial state of the button (default is False).

+
+
+
+
+clickedWhileActive
+

Emitted when the button is clicked while it is in the active state.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+clickedWhileInactive
+

Emitted when the button is clicked while it is in the inactive state.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+stateChanged
+

Emitted when the button’s state has changed. The signal carries the new state.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+__init__(*args, active=False, **kwargs)[source]
+

Initialize the StateButton with the specified active state.

+
+
Parameters:
+
    +
  • *args (tuple) – Positional arguments to be passed to the QPushButton constructor.

  • +
  • active (bool, optional) – Initial state of the button (default is False).

  • +
  • **kwargs (dict) – Keyword arguments to be passed to the QPushButton constructor.

  • +
+
+
Parameters:
+

active (bool)

+
+
+
+ +
+
+setActive(active)[source]
+

Set the active state of the button.

+

Emits stateChanged if the state has changed.

+
+
Parameters:
+

active (bool) – The new active state of the button.

+
+
Parameters:
+

active (bool)

+
+
+
+ +
+
+clickedWhileActive
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+clickedWhileInactive
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+isActive
+
+
pyqtProperty(type, fget=None, fset=None, freset=None, fdel=None, doc=None,

designable=True, scriptable=True, stored=True, user=False, +constant=False, final=False, notify=None, +revision=0) -> property attribute

+
+
+

type is the type of the property. It is either a type object or a string +that is the name of a C++ type. +freset is a function for resetting an attribute to its default value. +designable sets the DESIGNABLE flag (the default is True for writable +properties and False otherwise). +scriptable sets the SCRIPTABLE flag. +stored sets the STORED flag. +user sets the USER flag. +constant sets the CONSTANT flag. +final sets the FINAL flag. +notify is the NOTIFY signal. +revision is the REVISION. +The other parameters are the same as those required by the standard Python +property type. Properties defined using pyqtProperty behave as both Python +and Qt properties. +Decorators can be used to define new properties or to modify existing ones.

+
+ +
+
+stateChanged
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.Worker.html b/api/iblrig.gui.tools.Worker.html new file mode 100644 index 000000000..cb74f8176 --- /dev/null +++ b/api/iblrig.gui.tools.Worker.html @@ -0,0 +1,312 @@ + + + + + + + iblrig.gui.tools.Worker — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.Worker

+
Inheritance diagram of Worker
+ + +
+

+
+
+
+class iblrig.gui.tools.Worker[source]
+

A generic worker class for executing functions concurrently in a separate thread.

+

This class is designed to run functions concurrently in a separate thread and emit signals +to communicate the results or errors back to the main thread.

+

Adapted from: https://www.pythonguis.com/tutorials/multithreading-pyqt-applications-qthreadpool/

+
+
+fn
+

The function to be executed concurrently.

+
+
Type:
+

Callable

+
+
+
+ +
+
+args
+

Positional arguments for the function.

+
+
Type:
+

tuple

+
+
+
+ +
+
+kwargs
+

Keyword arguments for the function.

+
+
Type:
+

dict

+
+
+
+ +
+
+signals
+

An instance of WorkerSignals used to emit signals.

+
+
Type:
+

WorkerSignals

+
+
+
+ +
+
+run() None[source]
+

The main entry point for running the worker. Executes the provided function and +emits signals accordingly.

+
+
Return type:
+

None

+
+
+
+ +
+
+__init__(fn, *args, **kwargs)[source]
+

Initialize the Worker instance.

+
+
Parameters:
+
    +
  • fn (Callable) – The function to be executed concurrently.

  • +
  • *args (tuple) – Positional arguments for the function.

  • +
  • **kwargs (dict) – Keyword arguments for the function.

  • +
+
+
Parameters:
+
+
+
+
+ +
+
+run()[source]
+

Execute the provided function and emit signals accordingly.

+

This method is the main entry point for running the worker. It executes the provided +function and emits signals to communicate the results or errors back to the main thread.

+
+
Return type:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.WorkerSignals.html b/api/iblrig.gui.tools.WorkerSignals.html new file mode 100644 index 000000000..6a210b5eb --- /dev/null +++ b/api/iblrig.gui.tools.WorkerSignals.html @@ -0,0 +1,344 @@ + + + + + + + iblrig.gui.tools.WorkerSignals — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.WorkerSignals

+
Inheritance diagram of WorkerSignals
+ + +
+

+
+
+
+class iblrig.gui.tools.WorkerSignals[source]
+

Signals used by the Worker class to communicate with the main thread.

+
+
+finished
+

Signal emitted when the worker has finished its task.

+
+
Type:
+

pyqtSignal

+
+
+
+ +
+
+error
+

Signal emitted when an error occurs. The signal carries a tuple with the exception type, +exception value, and the formatted traceback.

+
+
Type:
+

pyqtSignal(tuple)

+
+
+
+ +
+
+result
+

Signal emitted when the worker has successfully completed its task. The signal carries +the result of the task.

+
+
Type:
+

pyqtSignal(Any)

+
+
+
+ +
+
+progress
+

Signal emitted to report progress during the task. The signal carries an integer value.

+
+
Type:
+

pyqtSignal(int)

+
+
+
+ +
+
+error
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+finished
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+progress
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+result
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.convert_uis.html b/api/iblrig.gui.tools.convert_uis.html new file mode 100644 index 000000000..432528298 --- /dev/null +++ b/api/iblrig.gui.tools.convert_uis.html @@ -0,0 +1,212 @@ + + + + + + + iblrig.gui.tools.convert_uis — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools.convert_uis

+
+
+iblrig.gui.tools.convert_uis()[source]
+

A wrapper for PyQt5’s pyuic5 and pyrcc5, set up for development on iblrig.

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.tools.html b/api/iblrig.gui.tools.html new file mode 100644 index 000000000..7dead5afd --- /dev/null +++ b/api/iblrig.gui.tools.html @@ -0,0 +1,245 @@ + + + + + + + iblrig.gui.tools — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.tools

+

Functions

+ + + + + + +

convert_uis

A wrapper for PyQt5's pyuic5 and pyrcc5, set up for development on iblrig.

+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

AlyxObject

A class to manage user authentication with an AlyxClient.

DataFrameTableModel

DiskSpaceIndicator

A custom progress bar widget that indicates the disk space usage of a specified directory.

LineEditAlyxUser

A custom QLineEdit widget for managing user login with an AlyxObject.

RemoteDevicesItemModel

RemoteDevicesListView

StatefulButton

A QPushButton that maintains an active/inactive state and emits different signals based on its state when clicked.

Worker

A generic worker class for executing functions concurrently in a separate thread.

WorkerSignals

Signals used by the Worker class to communicate with the main thread.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.html b/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.html new file mode 100644 index 000000000..f10bea3b9 --- /dev/null +++ b/api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_frame2ttl.Ui_frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_frame2ttl.Ui_frame2ttl

+
Inheritance diagram of Ui_frame2ttl
+ + +
+

+
+
+
+class iblrig.gui.ui_frame2ttl.Ui_frame2ttl[source]
+
+
+retranslateUi(frame2ttl)[source]
+
+ +
+
+setupUi(frame2ttl)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_frame2ttl.html b/api/iblrig.gui.ui_frame2ttl.html new file mode 100644 index 000000000..b234ae7b0 --- /dev/null +++ b/api/iblrig.gui.ui_frame2ttl.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_frame2ttl — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_frame2ttl

+

Classes

+ + + + + + +

Ui_frame2ttl

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_login.Ui_login.html b/api/iblrig.gui.ui_login.Ui_login.html new file mode 100644 index 000000000..c98e99f94 --- /dev/null +++ b/api/iblrig.gui.ui_login.Ui_login.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_login.Ui_login — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_login.Ui_login

+
Inheritance diagram of Ui_login
+ + +
+

+
+
+
+class iblrig.gui.ui_login.Ui_login[source]
+
+
+retranslateUi(login)[source]
+
+ +
+
+setupUi(login)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_login.html b/api/iblrig.gui.ui_login.html new file mode 100644 index 000000000..0325e65d7 --- /dev/null +++ b/api/iblrig.gui.ui_login.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_login — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_login

+

Classes

+ + + + + + +

Ui_login

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_splash.Ui_splash.html b/api/iblrig.gui.ui_splash.Ui_splash.html new file mode 100644 index 000000000..1bdb1cf7e --- /dev/null +++ b/api/iblrig.gui.ui_splash.Ui_splash.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_splash.Ui_splash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_splash.Ui_splash

+
Inheritance diagram of Ui_splash
+ + +
+

+
+
+
+class iblrig.gui.ui_splash.Ui_splash[source]
+
+
+retranslateUi(splash)[source]
+
+ +
+
+setupUi(splash)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_splash.html b/api/iblrig.gui.ui_splash.html new file mode 100644 index 000000000..d98222800 --- /dev/null +++ b/api/iblrig.gui.ui_splash.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_splash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_splash

+

Classes

+ + + + + + +

Ui_splash

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_about.Ui_TabAbout.html b/api/iblrig.gui.ui_tab_about.Ui_TabAbout.html new file mode 100644 index 000000000..8398c266e --- /dev/null +++ b/api/iblrig.gui.ui_tab_about.Ui_TabAbout.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_tab_about.Ui_TabAbout — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_about.Ui_TabAbout

+
Inheritance diagram of Ui_TabAbout
+ + +
+

+
+
+
+class iblrig.gui.ui_tab_about.Ui_TabAbout[source]
+
+
+retranslateUi(TabAbout)[source]
+
+ +
+
+setupUi(TabAbout)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_about.html b/api/iblrig.gui.ui_tab_about.html new file mode 100644 index 000000000..4379b3bb1 --- /dev/null +++ b/api/iblrig.gui.ui_tab_about.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_tab_about — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_about

+

Classes

+ + + + + + +

Ui_TabAbout

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_data.Ui_TabData.html b/api/iblrig.gui.ui_tab_data.Ui_TabData.html new file mode 100644 index 000000000..6ed488314 --- /dev/null +++ b/api/iblrig.gui.ui_tab_data.Ui_TabData.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_tab_data.Ui_TabData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_data.Ui_TabData

+
Inheritance diagram of Ui_TabData
+ + +
+

+
+
+
+class iblrig.gui.ui_tab_data.Ui_TabData[source]
+
+
+retranslateUi(TabData)[source]
+
+ +
+
+setupUi(TabData)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_data.html b/api/iblrig.gui.ui_tab_data.html new file mode 100644 index 000000000..b2a4f8c42 --- /dev/null +++ b/api/iblrig.gui.ui_tab_data.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_tab_data — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_data

+

Classes

+ + + + + + +

Ui_TabData

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.html b/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.html new file mode 100644 index 000000000..95fdeabb8 --- /dev/null +++ b/api/iblrig.gui.ui_tab_docs.Ui_TabDocs.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_tab_docs.Ui_TabDocs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_docs.Ui_TabDocs

+
Inheritance diagram of Ui_TabDocs
+ + +
+

+
+
+
+class iblrig.gui.ui_tab_docs.Ui_TabDocs[source]
+
+
+retranslateUi(TabDocs)[source]
+
+ +
+
+setupUi(TabDocs)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_docs.html b/api/iblrig.gui.ui_tab_docs.html new file mode 100644 index 000000000..2a820d6f8 --- /dev/null +++ b/api/iblrig.gui.ui_tab_docs.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_tab_docs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_docs

+

Classes

+ + + + + + +

Ui_TabDocs

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_log.Ui_TabLog.html b/api/iblrig.gui.ui_tab_log.Ui_TabLog.html new file mode 100644 index 000000000..146d3230c --- /dev/null +++ b/api/iblrig.gui.ui_tab_log.Ui_TabLog.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_tab_log.Ui_TabLog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_log.Ui_TabLog

+
Inheritance diagram of Ui_TabLog
+ + +
+

+
+
+
+class iblrig.gui.ui_tab_log.Ui_TabLog[source]
+
+
+retranslateUi(TabLog)[source]
+
+ +
+
+setupUi(TabLog)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_log.html b/api/iblrig.gui.ui_tab_log.html new file mode 100644 index 000000000..4f500297f --- /dev/null +++ b/api/iblrig.gui.ui_tab_log.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_tab_log — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_log

+

Classes

+ + + + + + +

Ui_TabLog

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_session.Ui_tabSession.html b/api/iblrig.gui.ui_tab_session.Ui_tabSession.html new file mode 100644 index 000000000..1f29fdeb4 --- /dev/null +++ b/api/iblrig.gui.ui_tab_session.Ui_tabSession.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_tab_session.Ui_tabSession — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_session.Ui_tabSession

+
Inheritance diagram of Ui_tabSession
+ + +
+

+
+
+
+class iblrig.gui.ui_tab_session.Ui_tabSession[source]
+
+
+retranslateUi(tabSession)[source]
+
+ +
+
+setupUi(tabSession)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_tab_session.html b/api/iblrig.gui.ui_tab_session.html new file mode 100644 index 000000000..0dfa599f9 --- /dev/null +++ b/api/iblrig.gui.ui_tab_session.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_tab_session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_tab_session

+

Classes

+ + + + + + +

Ui_tabSession

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_update.Ui_update.html b/api/iblrig.gui.ui_update.Ui_update.html new file mode 100644 index 000000000..b2a9bfc90 --- /dev/null +++ b/api/iblrig.gui.ui_update.Ui_update.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_update.Ui_update — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_update.Ui_update

+
Inheritance diagram of Ui_update
+ + +
+

+
+
+
+class iblrig.gui.ui_update.Ui_update[source]
+
+
+retranslateUi(update)[source]
+
+ +
+
+setupUi(update)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_update.html b/api/iblrig.gui.ui_update.html new file mode 100644 index 000000000..453c9b167 --- /dev/null +++ b/api/iblrig.gui.ui_update.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_update — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_update

+

Classes

+ + + + + + +

Ui_update

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_validation.Ui_validation.html b/api/iblrig.gui.ui_validation.Ui_validation.html new file mode 100644 index 000000000..d3b799248 --- /dev/null +++ b/api/iblrig.gui.ui_validation.Ui_validation.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_validation.Ui_validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_validation.Ui_validation

+
Inheritance diagram of Ui_validation
+ + +
+

+
+
+
+class iblrig.gui.ui_validation.Ui_validation[source]
+
+
+retranslateUi(validation)[source]
+
+ +
+
+setupUi(validation)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_validation.html b/api/iblrig.gui.ui_validation.html new file mode 100644 index 000000000..2654cbe11 --- /dev/null +++ b/api/iblrig.gui.ui_validation.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_validation

+

Classes

+ + + + + + +

Ui_validation

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_valve.Ui_valve.html b/api/iblrig.gui.ui_valve.Ui_valve.html new file mode 100644 index 000000000..b4d93036e --- /dev/null +++ b/api/iblrig.gui.ui_valve.Ui_valve.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_valve.Ui_valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_valve.Ui_valve

+
Inheritance diagram of Ui_valve
+ + +
+

+
+
+
+class iblrig.gui.ui_valve.Ui_valve[source]
+
+
+retranslateUi(valve)[source]
+
+ +
+
+setupUi(valve)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_valve.html b/api/iblrig.gui.ui_valve.html new file mode 100644 index 000000000..076bedf4e --- /dev/null +++ b/api/iblrig.gui.ui_valve.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_valve

+

Classes

+ + + + + + +

Ui_valve

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_wizard.Ui_wizard.html b/api/iblrig.gui.ui_wizard.Ui_wizard.html new file mode 100644 index 000000000..0c2b213c9 --- /dev/null +++ b/api/iblrig.gui.ui_wizard.Ui_wizard.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.gui.ui_wizard.Ui_wizard — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_wizard.Ui_wizard

+
Inheritance diagram of Ui_wizard
+ + +
+

+
+
+
+class iblrig.gui.ui_wizard.Ui_wizard[source]
+
+
+retranslateUi(wizard)[source]
+
+ +
+
+setupUi(wizard)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.ui_wizard.html b/api/iblrig.gui.ui_wizard.html new file mode 100644 index 000000000..64a2bd235 --- /dev/null +++ b/api/iblrig.gui.ui_wizard.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.gui.ui_wizard — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.ui_wizard

+

Classes

+ + + + + + +

Ui_wizard

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.validation.StatusItem.html b/api/iblrig.gui.validation.StatusItem.html new file mode 100644 index 000000000..96a54a28a --- /dev/null +++ b/api/iblrig.gui.validation.StatusItem.html @@ -0,0 +1,232 @@ + + + + + + + iblrig.gui.validation.StatusItem — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.validation.StatusItem

+
Inheritance diagram of StatusItem
+ + +
+

+
+
+
+class iblrig.gui.validation.StatusItem[source]
+
+
+__init__(status)[source]
+
+
Parameters:
+

status (Status)

+
+
+
+ +
+
+property status
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.validation.SystemValidationDialog.html b/api/iblrig.gui.validation.SystemValidationDialog.html new file mode 100644 index 000000000..fb8392140 --- /dev/null +++ b/api/iblrig.gui.validation.SystemValidationDialog.html @@ -0,0 +1,361 @@ + + + + + + + iblrig.gui.validation.SystemValidationDialog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.validation.SystemValidationDialog

+
Inheritance diagram of SystemValidationDialog
+ + + +
+

+
+
+
+class iblrig.gui.validation.SystemValidationDialog[source]
+
+
+__init__(*args, hardware_settings, rig_settings, **kwargs)[source]
+

Dialog for system validation.

+
+
Parameters:
+
    +
  • *args – Arguments to pass to the QDialog constructor.

  • +
  • hardware_settings (HardwareSettings) – Pydantic model with data parsed from hardware_settings.yaml

  • +
  • rig_settings (RigSettings) – Pydantic model with data parsed from iblrig_settings.yaml

  • +
  • **kwargs – Keyword arguments to pass to the QDialog constructor.

  • +
+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+on_item_finished(idx, status)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+on_item_result(idx, result)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+on_item_started(idx)[source]
+
+
Parameters:
+

idx (int)

+
+
+
+ +
+
+run()[source]
+

Prepare GUI and start worker thread for running validators.

+
+ +
+
+run_subprocess()[source]
+

Run all validators in a subprocess.

+
+ +
+
+item_finished
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+item_result
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+item_started
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+status_items: list[StatusItem] = []
+
+ +
+
+validator_items: list[ValidatorItem] = []
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.validation.ValidatorItem.html b/api/iblrig.gui.validation.ValidatorItem.html new file mode 100644 index 000000000..05cf96894 --- /dev/null +++ b/api/iblrig.gui.validation.ValidatorItem.html @@ -0,0 +1,246 @@ + + + + + + + iblrig.gui.validation.ValidatorItem — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.validation.ValidatorItem

+
Inheritance diagram of ValidatorItem
+ + +
+

+
+
+
+class iblrig.gui.validation.ValidatorItem[source]
+
+
+__init__(validator, hardware_settings, rig_settings)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+clear()[source]
+
+ +
+
+property status: Status
+
+ +
+
+validator: Validator
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.validation.html b/api/iblrig.gui.validation.html new file mode 100644 index 000000000..c07a2214b --- /dev/null +++ b/api/iblrig.gui.validation.html @@ -0,0 +1,219 @@ + + + + + + + iblrig.gui.validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.validation

+

Classes

+ + + + + + + + + + + + +

StatusItem

SystemValidationDialog

ValidatorItem

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.valve.CalibrationPlot.html b/api/iblrig.gui.valve.CalibrationPlot.html new file mode 100644 index 000000000..805687894 --- /dev/null +++ b/api/iblrig.gui.valve.CalibrationPlot.html @@ -0,0 +1,247 @@ + + + + + + + iblrig.gui.valve.CalibrationPlot — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.valve.CalibrationPlot

+
Inheritance diagram of CalibrationPlot
+ + +
+

+
+
+
+class iblrig.gui.valve.CalibrationPlot[source]
+
+
+__init__(parent, name, color, values=None)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+clear()[source]
+
+ +
+
+update()[source]
+
+ +
+
+property values: ValveValues
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.valve.ValveCalibrationDialog.html b/api/iblrig.gui.valve.ValveCalibrationDialog.html new file mode 100644 index 000000000..cd921c6c8 --- /dev/null +++ b/api/iblrig.gui.valve.ValveCalibrationDialog.html @@ -0,0 +1,492 @@ + + + + + + + iblrig.gui.valve.ValveCalibrationDialog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.valve.ValveCalibrationDialog

+
Inheritance diagram of ValveCalibrationDialog
+ + + +
+

+
+
+
+class iblrig.gui.valve.ValveCalibrationDialog[source]
+
+
+__init__(*args, **kwargs)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+calibrate()[source]
+
+ +
+
+clear_calibration()[source]
+
+ +
+
+clear_crop_callback(initial_grams, duration_s=0.05)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+clear_drop()[source]
+
+ +
+
+closeEvent(event)[source]
+
+ +
+
+define_and_start_state_machine(use_scale=False)[source]
+
+
Parameters:
+

use_scale (bool)

+
+
Return type:
+

None

+
+
+
+ +
+
+display_scale_stable(value)[source]
+
+
Parameters:
+

value (bool)

+
+
+
+ +
+
+display_scale_text(value)[source]
+
+
Parameters:
+

value (str)

+
+
+
+ +
+
+get_next_calibration_time()[source]
+
+
Return type:
+

float | None

+
+
+
+ +
+
+get_scale_reading()[source]
+
+ +
+
+initialize_scale(port)[source]
+
+
Parameters:
+

port (str)

+
+
Return type:
+

bool

+
+
+
+ +
+
+pulse_valve()[source]
+
+ +
+
+save()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+tare()[source]
+
+ +
+
+toggle_valve()[source]
+
+ +
+
+calibration_finished
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+drop_cleared
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+scale: Scale | None = None
+
+ +
+
+scale_initialized
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+scale_stable_changed
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+scale_text_changed
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+start_next_calibration
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+tared
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.valve.html b/api/iblrig.gui.valve.html new file mode 100644 index 000000000..66386a168 --- /dev/null +++ b/api/iblrig.gui.valve.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.gui.valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.valve

+

Classes

+ + + + + + + + + +

CalibrationPlot

ValveCalibrationDialog

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.wizard.LoginWindow.html b/api/iblrig.gui.wizard.LoginWindow.html new file mode 100644 index 000000000..152470034 --- /dev/null +++ b/api/iblrig.gui.wizard.LoginWindow.html @@ -0,0 +1,233 @@ + + + + + + + iblrig.gui.wizard.LoginWindow — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.wizard.LoginWindow

+
Inheritance diagram of LoginWindow
+ + + +
+

+
+
+
+class iblrig.gui.wizard.LoginWindow[source]
+
+
+__init__(parent, username='', password='', remember=False)[source]
+
+
Parameters:
+
+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.wizard.RigWizard.html b/api/iblrig.gui.wizard.RigWizard.html new file mode 100644 index 000000000..f7007544b --- /dev/null +++ b/api/iblrig.gui.wizard.RigWizard.html @@ -0,0 +1,336 @@ + + + + + + + iblrig.gui.wizard.RigWizard — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.wizard.RigWizard

+
Inheritance diagram of RigWizard
+ + + +
+

+
+
+
+class iblrig.gui.wizard.RigWizard[source]
+
+
+__init__(debug=False, remote_devices=False)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+closeEvent(event)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+controller2model()[source]
+
+ +
+
+eventFilter(obj, event)[source]
+
+ +
+
+flush()[source]
+
+ +
+
+model2view()[source]
+
+ +
+
+pause()[source]
+
+ +
+
+start_stop()[source]
+
+ +
+
+toggle_status_led(is_toggled)[source]
+
+
Parameters:
+

is_toggled (bool)

+
+
+
+ +
+
+append_session: bool = False
+
+ +
+
+property hardware_settings: HardwareSettings
+
+ +
+
+property iblrig_settings: RigSettings
+
+ +
+
+new_subject_details
+

str = …, revision: int = …, arguments: Sequence = …) -> PYQT_SIGNAL

+

types is normally a sequence of individual types. Each type is either a +type object or a string that is the name of a C++ type. Alternatively +each type could itself be a sequence of types each describing a different +overloaded signal. +name is the optional C++ name of the signal. If it is not specified then +the name of the class attribute that is bound to the signal is used. +revision is the optional revision of the signal that is exported to QML. +If it is not specified then 0 is used. +arguments is the optional sequence of the names of the signal’s arguments.

+
+
Type:
+

pyqtSignal(*types, name

+
+
+
+ +
+
+previous_subject: str | None = None
+
+ +
+
+session_info: dict = {}
+
+ +
+
+task_parameters: dict | None = None
+
+ +
+
+training_info: dict = {}
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.wizard.RigWizardModel.html b/api/iblrig.gui.wizard.RigWizardModel.html new file mode 100644 index 000000000..bfd1011f7 --- /dev/null +++ b/api/iblrig.gui.wizard.RigWizardModel.html @@ -0,0 +1,391 @@ + + + + + + + iblrig.gui.wizard.RigWizardModel — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.wizard.RigWizardModel

+
Inheritance diagram of RigWizardModel
+ + +
+

+
+
+
+class iblrig.gui.wizard.RigWizardModel[source]
+

RigWizardModel(alyx: one.webclient.AlyxClient | None = None, procedures: list | None = None, projects: list | None = None, task_name: str | None = None, user: str | None = None, subject: str | None = None, session_folder: pathlib.Path | None = None, free_reward_time: float | None = None, file_iblrig_settings: pathlib.Path | str | None = None, file_hardware_settings: pathlib.Path | str | None = None)

+
+
+__init__(alyx=None, procedures=None, projects=None, task_name=None, user=None, subject=None, session_folder=None, free_reward_time=None, file_iblrig_settings=None, file_hardware_settings=None)
+
+
Parameters:
+
    +
  • alyx (AlyxClient | None)

  • +
  • procedures (list | None)

  • +
  • projects (list | None)

  • +
  • task_name (str | None)

  • +
  • user (str | None)

  • +
  • subject (str | None)

  • +
  • session_folder (Path | None)

  • +
  • free_reward_time (float | None)

  • +
  • file_iblrig_settings (str | Path | None)

  • +
  • file_hardware_settings (str | Path | None)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+free_reward()[source]
+
+ +
+
+get_session(task_name)[source]
+

Get a session object for the given task name.

+
+
Parameters:
+

task_name (str) – The name of the task

+
+
Returns:
+

The session object for the given task name

+
+
Return type:
+

BaseSession

+
+
Parameters:
+

task_name (str)

+
+
+
+ +
+
+get_task_extra_parser(task_name)[source]
+

Get an extra parser for the given task name.

+
+
Parameters:
+

task_name – The name of the task

+
+
Returns:
+

The extra parser for the given task name

+
+
Return type:
+

ArgumentParser

+
+
Parameters:
+

task_name (str)

+
+
+
+ +
+
+get_task_parameters(task_name)[source]
+

Return parameters for the given task.

+
+
Parameters:
+

task_name – The name of the task

+
+
Returns:
+

The parameters for the given task

+
+
Return type:
+

Bunch

+
+
Parameters:
+

task_name (str)

+
+
+
+ +
+
+login(username, password=None, do_cache=False, alyx_client=None, gui=False)[source]
+
+
Parameters:
+
+
+
Return type:
+

bool

+
+
+
+ +
+
+logout()[source]
+
+ +
+
+alyx: AlyxClient | None = None
+
+ +
+
+file_hardware_settings: Path | str | None = None
+
+ +
+
+file_iblrig_settings: Path | str | None = None
+
+ +
+
+free_reward_time: float | None = None
+
+ +
+
+procedures: list | None = None
+
+ +
+
+projects: list | None = None
+
+ +
+
+session_folder: Path | None = None
+
+ +
+
+subject: str | None = None
+
+ +
+
+property task_file: Path
+
+ +
+
+task_name: str | None = None
+
+ +
+
+test_subject_name = 'test_subject'
+
+ +
+
+user: str | None = None
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.wizard.UpdateNotice.html b/api/iblrig.gui.wizard.UpdateNotice.html new file mode 100644 index 000000000..d7fa28a2e --- /dev/null +++ b/api/iblrig.gui.wizard.UpdateNotice.html @@ -0,0 +1,246 @@ + + + + + + + iblrig.gui.wizard.UpdateNotice — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.wizard.UpdateNotice

+
Inheritance diagram of UpdateNotice
+ + + +
+

+
+
+
+class iblrig.gui.wizard.UpdateNotice[source]
+

A dialog for displaying update notices.

+

This class is used to create a dialog for displaying update notices. +It shows information about the available update and provides a changelog.

+
+
Parameters:
+
    +
  • parent (QtWidgets.QWidget) – The parent widget associated with this dialog.

  • +
  • update_available (bool) – Indicates if an update is available.

  • +
  • version (str) – The version of the available update.

  • +
+
+
+
+
+__init__(parent, version)[source]
+
+
Parameters:
+
    +
  • parent (QWidget)

  • +
  • version (str)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.wizard.html b/api/iblrig.gui.wizard.html new file mode 100644 index 000000000..3fd5a0b5c --- /dev/null +++ b/api/iblrig.gui.wizard.html @@ -0,0 +1,230 @@ + + + + + + + iblrig.gui.wizard — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.wizard

+

Functions

+ + + + + + +

main

+

Classes

+ + + + + + + + + + + + + + + +

LoginWindow

RigWizard

RigWizardModel

RigWizardModel(alyx: one.webclient.AlyxClient | None = None, procedures: list | None = None, projects: list | None = None, task_name: str | None = None, user: str | None = None, subject: str | None = None, session_folder: pathlib.Path | None = None, free_reward_time: float | None = None, file_iblrig_settings: pathlib.Path | str | None = None, file_hardware_settings: pathlib.Path | str | None = None)

UpdateNotice

A dialog for displaying update notices.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.gui.wizard.main.html b/api/iblrig.gui.wizard.main.html new file mode 100644 index 000000000..08fbb840b --- /dev/null +++ b/api/iblrig.gui.wizard.main.html @@ -0,0 +1,211 @@ + + + + + + + iblrig.gui.wizard.main — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.gui.wizard.main

+
+
+iblrig.gui.wizard.main()[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware.Bpod.html b/api/iblrig.hardware.Bpod.html new file mode 100644 index 000000000..42fb91125 --- /dev/null +++ b/api/iblrig.hardware.Bpod.html @@ -0,0 +1,420 @@ + + + + + + + iblrig.hardware.Bpod — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware.Bpod

+
Inheritance diagram of Bpod
+ + +
+

+
+
+
+class iblrig.hardware.Bpod[source]
+
+
+__init__(*args, skip_initialization=False, **kwargs)[source]
+
+
Parameters:
+

skip_initialization (bool)

+
+
+
+ +
+
+static __new__(cls, *args, **kwargs)[source]
+
+ +
+
+close()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+define_harp_sounds_actions(module, go_tone_index=2, noise_index=3)[source]
+
+
Parameters:
+
    +
  • module (BpodModule)

  • +
  • go_tone_index (int)

  • +
  • noise_index (int)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+define_rotary_encoder_actions(module=None)[source]
+
+
Parameters:
+

module (BpodModule | None)

+
+
Return type:
+

None

+
+
+
+ +
+
+define_xonar_sounds_actions()[source]
+
+ +
+
+flush()[source]
+

Flushes valve 1.

+
+ +
+
+get_ambient_sensor_reading()[source]
+
+ +
+
+get_module(module_name)[source]
+

Get module by name.

+
+
Parameters:
+

module_name (str) – Regular Expression for matching a module name

+
+
Returns:
+

First matching module or None

+
+
Return type:
+

BpodModule | None

+
+
Parameters:
+

module_name (str)

+
+
+
+ +
+
+open_valve(open, valve_number=1)[source]
+
+
Parameters:
+
    +
  • open (bool)

  • +
  • valve_number (int)

  • +
+
+
+
+ +
+
+pulse_valve(open_time_s, valve='Valve1')[source]
+
+
Parameters:
+
+
+
+
+ +
+
+pulse_valve_repeatedly(repetitions, open_time_s, close_time_s=0.2, valve='Valve1')[source]
+
+
Parameters:
+
+
+
Return type:
+

int

+
+
+
+ +
+
+register_softcodes(softcode_dict)[source]
+

Register softcodes to be used in the state machine.

+
+
Parameters:
+

softcode_dict (dict[int, Callable]) – dictionary of int keys with callables as values

+
+
Parameters:
+

softcode_dict (dict[int, Callable])

+
+
Return type:
+

None

+
+
+
+ +
+
+set_status_led(state)[source]
+
+
Parameters:
+

state (bool)

+
+
Return type:
+

bool

+
+
+
+ +
+
+toggle_valve(duration=None)[source]
+

Flush valve 1 for specified duration.

+
+
Parameters:
+

duration (int, optional) – Duration of valve opening in seconds.

+
+
Parameters:
+

duration (int | None)

+
+
+
+ +
+
+valve(valve_id, state)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+property ambient_module
+
+ +
+
+can_control_led = True
+
+ +
+
+property is_connected
+
+ +
+
+property rotary_encoder
+
+ +
+
+softcodes: dict[int, Callable] | None = None
+
+ +
+
+property sound_card
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware.MyRotaryEncoder.html b/api/iblrig.hardware.MyRotaryEncoder.html new file mode 100644 index 000000000..d24bcddae --- /dev/null +++ b/api/iblrig.hardware.MyRotaryEncoder.html @@ -0,0 +1,208 @@ + + + + + + + iblrig.hardware.MyRotaryEncoder — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware.MyRotaryEncoder

+
Inheritance diagram of MyRotaryEncoder
+ + +
+

+
+
+
+class iblrig.hardware.MyRotaryEncoder[source]
+
+
+__init__(all_thresholds, gain, com, connect=False)[source]
+
+ +
+
+connect()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware.SOFTCODE.html b/api/iblrig.hardware.SOFTCODE.html new file mode 100644 index 000000000..d722b1134 --- /dev/null +++ b/api/iblrig.hardware.SOFTCODE.html @@ -0,0 +1,226 @@ + + + + + + + iblrig.hardware.SOFTCODE — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware.SOFTCODE

+
Inheritance diagram of SOFTCODE
+ + + + +
+

+
+
+
+class iblrig.hardware.SOFTCODE
+

An enumeration.

+
+
+__new__(value)
+
+ +
+
+PLAY_NOISE = 3
+
+ +
+
+PLAY_TONE = 2
+
+ +
+
+STOP_SOUND = 1
+
+ +
+
+TRIGGER_CAMERA = 4
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware.html b/api/iblrig.hardware.html new file mode 100644 index 000000000..94907f930 --- /dev/null +++ b/api/iblrig.hardware.html @@ -0,0 +1,212 @@ + + + + + + + iblrig.hardware — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware

+

Hardware classes used to interact with modules.

+

Functions

+ + + + + + + + + +

restart_com_port

Restart the communication port(s) matching the specified regular expression.

sound_device_factory

Will import, configure, and return sounddevice module to play sounds using onboard sound card.

+

Classes

+ + + + + + + + + + + + +

Bpod

MyRotaryEncoder

SOFTCODE

An enumeration.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware.restart_com_port.html b/api/iblrig.hardware.restart_com_port.html new file mode 100644 index 000000000..96f1de506 --- /dev/null +++ b/api/iblrig.hardware.restart_com_port.html @@ -0,0 +1,224 @@ + + + + + + + iblrig.hardware.restart_com_port — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware.restart_com_port

+
+
+iblrig.hardware.restart_com_port(regexp)[source]
+

Restart the communication port(s) matching the specified regular expression.

+
+
Parameters:
+

regexp (str) – A regular expression used to match the communication port(s).

+
+
Returns:
+

Returns True if all matched ports are successfully restarted, False otherwise.

+
+
Return type:
+

bool

+
+
Raises:
+
+
+
Parameters:
+

regexp (str)

+
+
+
+

Examples

+
>>> restart_com_port("COM3")  # Restart the communication port with serial number 'COM3'
+True
+
+
+
>>> restart_com_port("COM[1-3]")  # Restart communication ports with serial numbers 'COM1', 'COM2', 'COM3'
+True
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware.sound_device_factory.html b/api/iblrig.hardware.sound_device_factory.html new file mode 100644 index 000000000..4b461d718 --- /dev/null +++ b/api/iblrig.hardware.sound_device_factory.html @@ -0,0 +1,207 @@ + + + + + + + iblrig.hardware.sound_device_factory — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware.sound_device_factory

+
+
+iblrig.hardware.sound_device_factory(output='sysdefault', samplerate=None)[source]
+

Will import, configure, and return sounddevice module to play sounds using onboard sound card.

+
+
Parameters:
+
    +
  • output – defaults to “sysdefault”, should be ‘xonar’ or ‘harp’

  • +
  • samplerate – audio sample rate, defaults to 44100

  • +
+
+
Parameters:
+
    +
  • output (Literal['xonar', 'harp', 'hifi', 'sysdefault'])

  • +
  • samplerate (int | None)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.Result.html b/api/iblrig.hardware_validation.Result.html new file mode 100644 index 000000000..8a89ea807 --- /dev/null +++ b/api/iblrig.hardware_validation.Result.html @@ -0,0 +1,262 @@ + + + + + + + iblrig.hardware_validation.Result — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.Result

+
Inheritance diagram of Result
+ + +
+

+
+
+
+class iblrig.hardware_validation.Result[source]
+

Dataclass holding the results of a single validation.

+
+
+__init__(status, message, ext_message=None, solution=None, url=None, exception=None)
+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+exception: Exception | None = None
+
+ +
+
+ext_message: str | None = None
+
+ +
+
+message: str
+
+ +
+
+solution: str | None = None
+
+ +
+
+status: Status
+
+ +
+
+url: str | None = None
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.Status.html b/api/iblrig.hardware_validation.Status.html new file mode 100644 index 000000000..301dc25ef --- /dev/null +++ b/api/iblrig.hardware_validation.Status.html @@ -0,0 +1,249 @@ + + + + + + + iblrig.hardware_validation.Status — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.Status

+
Inheritance diagram of Status
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.Status[source]
+

Possible status codes of hardware validations.

+
+
+__new__(value)
+
+ +
+
+FAIL = 5
+
+ +
+
+INFO = 4
+
+ +
+
+PASS = 2
+
+ +
+
+PEND = 0
+
+ +
+
+SKIP = 1
+
+ +
+
+WARN = 3
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidateHardwareError.html b/api/iblrig.hardware_validation.ValidateHardwareError.html new file mode 100644 index 000000000..d54bb0a36 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidateHardwareError.html @@ -0,0 +1,210 @@ + + + + + + + iblrig.hardware_validation.ValidateHardwareError — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidateHardwareError

+
+
+exception iblrig.hardware_validation.ValidateHardwareError[source]
+
+
+__new__(**kwargs)
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.Validator.html b/api/iblrig.hardware_validation.Validator.html new file mode 100644 index 000000000..f157672a9 --- /dev/null +++ b/api/iblrig.hardware_validation.Validator.html @@ -0,0 +1,279 @@ + + + + + + + iblrig.hardware_validation.Validator — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.Validator

+
Inheritance diagram of Validator
+ + + +
+

+
+
+
+class iblrig.hardware_validation.Validator[source]
+
+
+__init__(iblrig_settings=None, hardware_settings=None, interactive=False)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+process(results)[source]
+
+
Parameters:
+

results (Result)

+
+
Return type:
+

Result

+
+
+
+ +
+
+run(*args, **kwargs)[source]
+
+
Return type:
+

Generator[Result, None, bool]

+
+
+
+ +
+
+hardware_settings: HardwareSettings
+
+ +
+
+iblrig_settings: RigSettings
+
+ +
+
+interactive: bool
+
+ +
+
+log_results: bool = True
+
+ +
+
+property name: str
+
+ +
+
+raise_fail_as_exception: bool = False
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorAlyx.html b/api/iblrig.hardware_validation.ValidatorAlyx.html new file mode 100644 index 000000000..c733d0395 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorAlyx.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.hardware_validation.ValidatorAlyx — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorAlyx

+
Inheritance diagram of ValidatorAlyx
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorAlyx[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorAmbientModule.html b/api/iblrig.hardware_validation.ValidatorAmbientModule.html new file mode 100644 index 000000000..dbb628f11 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorAmbientModule.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.hardware_validation.ValidatorAmbientModule — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorAmbientModule

+
Inheritance diagram of ValidatorAmbientModule
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorAmbientModule[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorBpod.html b/api/iblrig.hardware_validation.ValidatorBpod.html new file mode 100644 index 000000000..fc2668da6 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorBpod.html @@ -0,0 +1,229 @@ + + + + + + + iblrig.hardware_validation.ValidatorBpod — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorBpod

+
Inheritance diagram of ValidatorBpod
+ + + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorBpod[source]
+
+
+property port
+
+ +
+
+port_properties: dict[str, Any] = {'vid': 5824}
+
+ +
+
+serial_queries: None | dict[tuple[bytes, int], bytes] = {(b'6', 1): b'5'}
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorCamera.html b/api/iblrig.hardware_validation.ValidatorCamera.html new file mode 100644 index 000000000..99893e962 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorCamera.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.hardware_validation.ValidatorCamera — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorCamera

+
Inheritance diagram of ValidatorCamera
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorCamera[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorFrame2TTL.html b/api/iblrig.hardware_validation.ValidatorFrame2TTL.html new file mode 100644 index 000000000..e509cbdb6 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorFrame2TTL.html @@ -0,0 +1,224 @@ + + + + + + + iblrig.hardware_validation.ValidatorFrame2TTL — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorFrame2TTL

+
Inheritance diagram of ValidatorFrame2TTL
+ + + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorFrame2TTL[source]
+
+
+property port
+
+ +
+
+serial_queries: None | dict[tuple[bytes, int], bytes] = {(b'C', 1): b'\xda'}
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorGit.html b/api/iblrig.hardware_validation.ValidatorGit.html new file mode 100644 index 000000000..48a1de0f7 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorGit.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.hardware_validation.ValidatorGit — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorGit

+
Inheritance diagram of ValidatorGit
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorGit[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorMic.html b/api/iblrig.hardware_validation.ValidatorMic.html new file mode 100644 index 000000000..a8dc9385f --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorMic.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.hardware_validation.ValidatorMic — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorMic

+
Inheritance diagram of ValidatorMic
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorMic[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.html b/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.html new file mode 100644 index 000000000..c4ece0ac1 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.html @@ -0,0 +1,229 @@ + + + + + + + iblrig.hardware_validation.ValidatorRotaryEncoderModule — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorRotaryEncoderModule

+
Inheritance diagram of ValidatorRotaryEncoderModule
+ + + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorRotaryEncoderModule[source]
+
+
+property port
+
+ +
+
+port_properties: dict[str, Any] = {'vid': 5824}
+
+ +
+
+serial_queries: None | dict[tuple[bytes, int], bytes] = {(b'P00', 1): b'\x01', (b'Q', 2): b'^..$'}
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorSerial.html b/api/iblrig.hardware_validation.ValidatorSerial.html new file mode 100644 index 000000000..3709fe8fd --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorSerial.html @@ -0,0 +1,238 @@ + + + + + + + iblrig.hardware_validation.ValidatorSerial — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorSerial

+
Inheritance diagram of ValidatorSerial
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorSerial[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+abstract property port: str | None
+
+ +
+
+property port_info: ListPortInfo | None
+
+ +
+
+port_properties: dict[str, Any] = {}
+
+ +
+
+serial_queries: None | dict[tuple[bytes, int], bytes] = None
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorSound.html b/api/iblrig.hardware_validation.ValidatorSound.html new file mode 100644 index 000000000..1ef4eed75 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorSound.html @@ -0,0 +1,224 @@ + + + + + + + iblrig.hardware_validation.ValidatorSound — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorSound

+
Inheritance diagram of ValidatorSound
+ + + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorSound[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+property port: str | None
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.ValidatorValve.html b/api/iblrig.hardware_validation.ValidatorValve.html new file mode 100644 index 000000000..81aef1639 --- /dev/null +++ b/api/iblrig.hardware_validation.ValidatorValve.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.hardware_validation.ValidatorValve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.ValidatorValve

+
Inheritance diagram of ValidatorValve
+ + + + +
+

+
+
+
+class iblrig.hardware_validation.ValidatorValve[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.get_all_validators.html b/api/iblrig.hardware_validation.get_all_validators.html new file mode 100644 index 000000000..774b5e798 --- /dev/null +++ b/api/iblrig.hardware_validation.get_all_validators.html @@ -0,0 +1,210 @@ + + + + + + + iblrig.hardware_validation.get_all_validators — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.get_all_validators

+
+
+iblrig.hardware_validation.get_all_validators()[source]
+
+
Return type:
+

list[type[Validator]]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.html b/api/iblrig.hardware_validation.html new file mode 100644 index 000000000..7bb17ab79 --- /dev/null +++ b/api/iblrig.hardware_validation.html @@ -0,0 +1,268 @@ + + + + + + + iblrig.hardware_validation — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation

+

Functions

+ + + + + + + + + + + + +

get_all_validators

run_all_validators

run_all_validators_cli

+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Result

Dataclass holding the results of a single validation.

Status

Possible status codes of hardware validations.

Validator

ValidatorAlyx

ValidatorAmbientModule

ValidatorBpod

ValidatorCamera

ValidatorFrame2TTL

ValidatorGit

ValidatorMic

ValidatorRotaryEncoderModule

ValidatorSerial

ValidatorSound

ValidatorValve

+

Exceptions

+ + + + + + +

ValidateHardwareError

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.run_all_validators.html b/api/iblrig.hardware_validation.run_all_validators.html new file mode 100644 index 000000000..f9b16b08e --- /dev/null +++ b/api/iblrig.hardware_validation.run_all_validators.html @@ -0,0 +1,217 @@ + + + + + + + iblrig.hardware_validation.run_all_validators — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.run_all_validators

+
+
+iblrig.hardware_validation.run_all_validators(iblrig_settings=None, hardware_settings=None, interactive=False)[source]
+
+
Parameters:
+
+
+
Return type:
+

Generator[Result, None, None]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hardware_validation.run_all_validators_cli.html b/api/iblrig.hardware_validation.run_all_validators_cli.html new file mode 100644 index 000000000..f13807757 --- /dev/null +++ b/api/iblrig.hardware_validation.run_all_validators_cli.html @@ -0,0 +1,205 @@ + + + + + + + iblrig.hardware_validation.run_all_validators_cli — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hardware_validation.run_all_validators_cli

+
+
+iblrig.hardware_validation.run_all_validators_cli()[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hifi.HiFi.html b/api/iblrig.hifi.HiFi.html new file mode 100644 index 000000000..34529bb5c --- /dev/null +++ b/api/iblrig.hifi.HiFi.html @@ -0,0 +1,305 @@ + + + + + + + iblrig.hifi.HiFi — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.hifi.HiFi

+
Inheritance diagram of HiFi
+ + + + + +
+

+
+
+
+class iblrig.hifi.HiFi[source]
+
+
+__init__(*args, sampling_rate_hz=192000, attenuation_db=0, **kwargs)[source]
+
+
Parameters:
+
    +
  • sampling_rate_hz (int)

  • +
  • attenuation_db (int)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+handshake()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+load(index, data, loop_mode=False, loop_duration=0)[source]
+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+play(index)[source]
+
+
Parameters:
+

index (int)

+
+
Return type:
+

None

+
+
+
+ +
+
+push()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+stop(index=None)[source]
+
+
Parameters:
+

index (int | None)

+
+
+
+ +
+
+property attenuation_db: float
+
+ +
+
+property bit_depth: int
+
+ +
+
+property is_hd: bool
+
+ +
+
+property max_envelope_samples: int
+
+ +
+
+property max_samples_per_waveform: int
+
+ +
+
+property sampling_rate_hz: int
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.hifi.HiFiException.html b/api/iblrig.hifi.HiFiException.html new file mode 100644 index 000000000..03196b69e --- /dev/null +++ b/api/iblrig.hifi.HiFiException.html @@ -0,0 +1,199 @@ + + + + + + + iblrig.hifi.HiFiException — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.hifi.html b/api/iblrig.hifi.html new file mode 100644 index 000000000..65243e9c7 --- /dev/null +++ b/api/iblrig.hifi.html @@ -0,0 +1,199 @@ + + + + + + + iblrig.hifi — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.html b/api/iblrig.html new file mode 100644 index 000000000..41c1a43e6 --- /dev/null +++ b/api/iblrig.html @@ -0,0 +1,267 @@ + + + + + + + iblrig — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig

+

Modules

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

base_choice_world

Extends the base_tasks modules by providing task logic around the Choice World protocol.

base_tasks

Commonalities for all tasks.

choiceworld

Choice World Task related logic and functions that translate the task description in Appendix 2 of the paper into code.

commands

constants

ephys

frame2ttl

graphic

Popup and string input prompts

gui

hardware

Hardware classes used to interact with modules.

hardware_validation

hifi

misc

Provides collection of functionality used throughout the iblrig repository.

net

Network communication between rigs.

online_plots

path_helper

pydantic_definitions

raw_data_loaders

rig_component

scale

serial_singleton

session_creator

Creates sessions, pre-generates stim and ephys sessions.

sound

tools

transfer_experiments

upgrade_iblrig

valve

version_management

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.draw_contrast.html b/api/iblrig.misc.draw_contrast.html new file mode 100644 index 000000000..7b39452a9 --- /dev/null +++ b/api/iblrig.misc.draw_contrast.html @@ -0,0 +1,226 @@ + + + + + + + iblrig.misc.draw_contrast — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.draw_contrast

+
+
+iblrig.misc.draw_contrast(contrast_set, probability_type='biased', idx=-1, idx_probability=0.5)[source]
+

Draw a contrast value from a given iterable based to the specified probability type.

+
+
Parameters:
+
    +
  • contrast_set (list[float]) – The set of contrast values from which to draw.

  • +
  • probability_type (Literal[``”skew_zero”, ``"biased", "uniform"], optional) – The type of probability distribution to use. +- “skew_zero” or “biased”: Draws with a biased probability distribution based on idx and idx_probability, +- “uniform”: Draws with a uniform probability distribution. +Defaults to “biased”.

  • +
  • idx (int, optional) – Index for probability manipulation (with “skew_zero” or “biased”), default: -1.

  • +
  • idx_probability (float, optional) – Probability for the specified index (with “skew_zero” or “biased”), default: 0.5.

  • +
+
+
Returns:
+

The drawn contrast value.

+
+
Return type:
+

float

+
+
Raises:
+

ValueError – If an unsupported probability_type is provided.

+
+
Parameters:
+
    +
  • contrast_set (list[float])

  • +
  • probability_type (Literal['skew_zero', 'biased', 'uniform'])

  • +
  • idx (int)

  • +
  • idx_probability (float)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.get_biased_probs.html b/api/iblrig.misc.get_biased_probs.html new file mode 100644 index 000000000..dc77a8a84 --- /dev/null +++ b/api/iblrig.misc.get_biased_probs.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.misc.get_biased_probs — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.get_biased_probs

+
+
+iblrig.misc.get_biased_probs(n, idx=-1, p_idx=0.5)[source]
+

Calculate biased probabilities for all elements of an array such that the +i`th value has probability `p_i for being drawn relative to the remaining +values.

+

See: https://github.com/int-brain-lab/iblrig/issues/74

+
+
Parameters:
+
    +
  • n (int) – The length of the array, i.e., the number of probabilities to generate.

  • +
  • idx (int, optional) – The index of the value that has the biased probability. Defaults to -1.

  • +
  • p_idx (float, optional) – The probability of the idx-th value relative to the rest. Defaults to 0.5.

  • +
+
+
Returns:
+

List of biased probabilities.

+
+
Return type:
+

List[float]

+
+
Raises:
+
+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.get_port_events.html b/api/iblrig.misc.get_port_events.html new file mode 100644 index 000000000..ab8d86fe6 --- /dev/null +++ b/api/iblrig.misc.get_port_events.html @@ -0,0 +1,206 @@ + + + + + + + iblrig.misc.get_port_events — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.get_port_events

+
+
+iblrig.misc.get_port_events(events, name='')[source]
+
+
Parameters:
+
+
+
Return type:
+

list

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.get_session_path.html b/api/iblrig.misc.get_session_path.html new file mode 100644 index 000000000..fa9f1f9e4 --- /dev/null +++ b/api/iblrig.misc.get_session_path.html @@ -0,0 +1,204 @@ + + + + + + + iblrig.misc.get_session_path — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.get_session_path

+
+
+iblrig.misc.get_session_path(path)[source]
+

Returns the session path from any filepath if the date/number pattern is found.

+
+
Parameters:
+

path (str | Path)

+
+
Return type:
+

Path | None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.get_task_argument_parser.html b/api/iblrig.misc.get_task_argument_parser.html new file mode 100644 index 000000000..0f3f4b64e --- /dev/null +++ b/api/iblrig.misc.get_task_argument_parser.html @@ -0,0 +1,202 @@ + + + + + + + iblrig.misc.get_task_argument_parser — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.get_task_argument_parser

+
+
+iblrig.misc.get_task_argument_parser(parents=None)[source]
+

Return the task’s argument parser.

+

This function is kept separate from parsing for purposes of unit testing.

+
+
Parameters:
+

parents (Sequence[ArgumentParser] | None)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.get_task_arguments.html b/api/iblrig.misc.get_task_arguments.html new file mode 100644 index 000000000..762901e63 --- /dev/null +++ b/api/iblrig.misc.get_task_arguments.html @@ -0,0 +1,210 @@ + + + + + + + iblrig.misc.get_task_arguments — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.get_task_arguments

+
+
+iblrig.misc.get_task_arguments(parents=None)[source]
+

Parse input to run the tasks. All the variables are fed to the Session instance +task.py -s subject_name -p projects_name -c procedures_name –no-interactive +:param extra_args: list of dictionaries of additional argparse arguments to add to the parser

+
+

For example, to add a new toto and titi arguments, use: +get_task_arguments({’–toto’, type=str, default=’toto’}, {’–titi’, action=’store_true’, default=False})

+
+
+
Returns:
+

+
+
Parameters:
+

parents (Sequence[ArgumentParser] | None)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.html b/api/iblrig.misc.html new file mode 100644 index 000000000..a13366808 --- /dev/null +++ b/api/iblrig.misc.html @@ -0,0 +1,222 @@ + + + + + + + iblrig.misc — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc

+

Provides collection of functionality used throughout the iblrig repository.

+

Assortment of functions, frequently used, but without a great deal of commonality. Functions can, +and should, be broken out into their own files and/or classes as the organizational needs of this +repo change over time.

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

draw_contrast

Draw a contrast value from a given iterable based to the specified probability type.

get_biased_probs

Calculate biased probabilities for all elements of an array such that the i`th value has probability `p_i for being drawn relative to the remaining values.

get_port_events

get_session_path

Returns the session path from any filepath if the date/number pattern is found.

get_task_argument_parser

Return the task's argument parser.

get_task_arguments

Parse input to run the tasks. All the variables are fed to the Session instance task.py -s subject_name -p projects_name -c procedures_name --no-interactive :param extra_args: list of dictionaries of additional argparse arguments to add to the parser For example, to add a new toto and titi arguments, use: get_task_arguments({'--toto', type=str, default='toto'}, {'--titi', action='store_true', default=False}) :return:.

online_std

Update the mean and standard deviation of a group of values after a sample update.

truncated_exponential

Generate a truncated exponential random variable within a specified range.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.online_std.html b/api/iblrig.misc.online_std.html new file mode 100644 index 000000000..eb48a9394 --- /dev/null +++ b/api/iblrig.misc.online_std.html @@ -0,0 +1,220 @@ + + + + + + + iblrig.misc.online_std — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.online_std

+
+
+iblrig.misc.online_std(new_sample, new_count, old_mean, old_std)[source]
+

Update the mean and standard deviation of a group of values after a sample update.

+
+
Parameters:
+
    +
  • new_sample (float) – The new sample to be included.

  • +
  • new_count (int) – The new count of samples (including new_sample).

  • +
  • old_mean (float) – The previous mean (N - 1).

  • +
  • old_std (float) – The previous standard deviation (N - 1).

  • +
+
+
Returns:
+

Updated mean and standard deviation.

+
+
Return type:
+

tuple[float, float]

+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.misc.truncated_exponential.html b/api/iblrig.misc.truncated_exponential.html new file mode 100644 index 000000000..043f7ea01 --- /dev/null +++ b/api/iblrig.misc.truncated_exponential.html @@ -0,0 +1,228 @@ + + + + + + + iblrig.misc.truncated_exponential — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.misc.truncated_exponential

+
+
+iblrig.misc.truncated_exponential(scale=0.35, min_value=0.2, max_value=0.5)[source]
+

Generate a truncated exponential random variable within a specified range.

+
+
Parameters:
+
    +
  • scale (float, optional) – Scale of the exponential distribution (inverse of rate parameter). Defaults to 0.35.

  • +
  • min_value (float, optional) – Minimum value for the truncated range. Defaults to 0.2.

  • +
  • max_value (float, optional) – Maximum value for the truncated range. Defaults to 0.5.

  • +
+
+
Returns:
+

Truncated exponential random variable.

+
+
Return type:
+

float

+
+
Parameters:
+
+
+
+
+

Notes

+

This function generates a random variable from an exponential distribution +with the specified scale. It then checks if the generated value is within +the specified range [min_value, max_value]. If it is within the range, it returns +the generated value; otherwise, it recursively generates a new value until it falls +within the specified range.

+

The scale should typically be greater than or equal to the min_value to avoid +potential issues with infinite recursion.

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.Auxiliaries.html b/api/iblrig.net.Auxiliaries.html new file mode 100644 index 000000000..9e86f67a6 --- /dev/null +++ b/api/iblrig.net.Auxiliaries.html @@ -0,0 +1,379 @@ + + + + + + + iblrig.net.Auxiliaries — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.Auxiliaries

+
Inheritance diagram of Auxiliaries
+ + +
+

+
+
+
+class iblrig.net.Auxiliaries[source]
+
+
+__init__(clients)[source]
+

Connect to and communicate with one or more remote rigs synchronously.

+
+
Parameters:
+

clients (dict[str, str]) – A map of name to URI.

+
+
+
+ +
+
+static __new__(cls, *args, **kwargs)[source]
+
+ +
+
+async cleanup(notify_services=False)[source]
+

Close connections and cleanup services.

+

This method closes all service communicators and cancels any pending callbacks.

+
+
Parameters:
+

notify_services (bool) – If true, send EXPCLEANUP message to remote devices before cleanup.

+
+
+
+ +
+
+clear_message_queue()[source]
+

Clear queued messages.

+
+
Returns:
+

The number of aborted messages.

+
+
Return type:
+

int

+
+
+
+ +
+
+close()[source]
+

Close communicators and wait for thread to terminate.

+
+ +
+
+async create()[source]
+

Create remote services object.

+

Instantiates communicator objects which establish the UDP connections, wraps them in the +Service class for bulk messaging, sets connected property to True and assigns some logging +callbacks. This should be called from a daemon thread.

+
+ +
+
+async listen()[source]
+

Listen for messages in queue and push to remote services.

+

Creates service communicators then awaits messages added to the queue. Once added, these +are sent to the remote services and the collated responses are added to the log. +Exits only after stop event is set. This should be called from a daemon thread.

+
+ +
+
+push(message, *args, wait=False, **kwargs)[source]
+

Queue message for dispatch to remote services.

+

This method synchronously logs the request time and pushes the message to the queue for the +asynchronous thread to handle.

+
+
Parameters:
+
    +
  • message (iblutil.io.net.base.ExpMessage) – An experiment message to send to remote services.

  • +
  • args (any) – One or more optional variables to send.

  • +
  • wait (bool) – If True, this method is blocking and once all messages are received (or timed out) the +collated responses are returned. Otherwise the request timestamp is returned for use as +a log key when fetching the responses in a non-blocking manner.

  • +
  • kwargs – Optional keyword arguments to use in calling communicator methods (currently unused).

  • +
+
+
Returns:
+

An exception if failed to receive all responses in time, otherwise a map of service +name and response if wait is true, or the request time if wait is false.

+
+
Return type:
+

Exception | dict | float

+
+
Raises:
+

RuntimeError – The async thread failed to return a response, most likely due to an error in the listen + method.

+
+
Parameters:
+

message (ExpMessage)

+
+
+
+ +
+
+connected = None
+

A thread event. Set by async thread once all services connected.

+
+
Type:
+

threading.Event

+
+
+
+ +
+
+property is_connected: bool
+

True if successfully connected to services.

+
+
Type:
+

bool

+
+
+
+ +
+
+property is_running: bool
+

True if listen is running on another thread.

+
+
Type:
+

bool

+
+
+
+ +
+
+refresh_rate = 0.2
+

How long to wait between checking message queue.

+
+
Type:
+

float

+
+
+
+ +
+
+response_received = None
+

A thread event. Notified each time the async thread receives all responses.

+
+
Type:
+

threading.Event

+
+
+
+ +
+
+services = None
+

A map of remote services.

+
+
Type:
+

iblutil.io.net.app.Services

+
+
+
+ +
+
+stop_event = None
+

A thread event. Once set, thread stops listening and clean up services.

+
+
Type:
+

threading.Event

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.ExpInfo.html b/api/iblrig.net.ExpInfo.html new file mode 100644 index 000000000..033445293 --- /dev/null +++ b/api/iblrig.net.ExpInfo.html @@ -0,0 +1,258 @@ + + + + + + + iblrig.net.ExpInfo — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.ExpInfo

+
Inheritance diagram of ExpInfo
+ + +
+

+
+
+
+class iblrig.net.ExpInfo[source]
+

A standard experiment information structure.

+
+
+__init__(exp_ref, main_sync, experiment_description=<factory>, master=False, rig_version='8.24.1', spec_version='1.0.0')
+
+
Parameters:
+
    +
  • exp_ref (str)

  • +
  • main_sync (bool)

  • +
  • experiment_description (dict)

  • +
  • master (bool)

  • +
  • rig_version (str)

  • +
  • spec_version (str)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+to_dict()[source]
+
+ +
+
+exp_ref: str
+
+ +
+
+experiment_description: dict
+
+ +
+
+main_sync: bool
+
+ +
+
+master: bool = False
+
+ +
+
+rig_version: str = '8.24.1'
+
+ +
+
+spec_version: str = '1.0.0'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.check_uri_match.html b/api/iblrig.net.check_uri_match.html new file mode 100644 index 000000000..fe7781ca7 --- /dev/null +++ b/api/iblrig.net.check_uri_match.html @@ -0,0 +1,224 @@ + + + + + + + iblrig.net.check_uri_match — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.check_uri_match

+
+
+async iblrig.net.check_uri_match(com, update=None)[source]
+

Log warning if URI in remote devices is wrong.

+

NB: Currently does not check if the protocol matches, and does not resolve hostnames.

+
+
Parameters:
+
    +
  • com (iblutil.io.net.app.EchoProtocol) – A Communicator instance to compare to the devices file.

  • +
  • update (bool, None) – If True, update the remote devices YAML file. If False, do not update the remote devices YAML file. If None, +only updates if the file exists.

  • +
+
+
Returns:
+

    +
  • iblutil.io.net.app.EchoProtocol – The same Communicator instance.

  • +
  • bool – True if the URI matches the one in the file, False otherwise. When update is True, True should always be +returned.

  • +
+

+
+
Raises:
+

FileNotFoundError – Raised when update is True but the remote devices YAML file does not exist on disk.

+
+
Parameters:
+

com (EchoProtocol)

+
+
Return type:
+

(<class ‘iblutil.io.net.app.EchoProtocol’>, <class ‘bool’>)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.get_remote_devices.html b/api/iblrig.net.get_remote_devices.html new file mode 100644 index 000000000..0c21ea947 --- /dev/null +++ b/api/iblrig.net.get_remote_devices.html @@ -0,0 +1,212 @@ + + + + + + + iblrig.net.get_remote_devices — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.get_remote_devices

+
+
+iblrig.net.get_remote_devices(remote_devices_file=None, iblrig_settings=None)[source]
+

Return map of device name to network URI.

+
+
Parameters:
+
    +
  • remote_devices_file (pathlib.Path) – Optional remote data path.

  • +
  • iblrig_settings (dict) – A settings dictionary, otherwise will load the default settings from file. Used to +determine the remote data path (the remote_data_folder param).

  • +
+
+
Returns:
+

A map of device name to network URI, e.g. {‘cameras’: ‘udp://127.0.0.1:11001’}.

+
+
Return type:
+

dict[str, str]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.get_remote_devices_file.html b/api/iblrig.net.get_remote_devices_file.html new file mode 100644 index 000000000..cd3607bf7 --- /dev/null +++ b/api/iblrig.net.get_remote_devices_file.html @@ -0,0 +1,208 @@ + + + + + + + iblrig.net.get_remote_devices_file — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.get_remote_devices_file

+
+
+iblrig.net.get_remote_devices_file(iblrig_settings=None)[source]
+

Return the location of the remote devices YAML file.

+
+
Parameters:
+

iblrig_settings (dict) – A settings dictionary, otherwise will load the default settings from file.

+
+
Returns:
+

The full path to the remote devices YAML file in the remote data folder, or None if the folder is not defined.

+
+
Return type:
+

pathlib.Path, None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.get_server_communicator.html b/api/iblrig.net.get_server_communicator.html new file mode 100644 index 000000000..3f278d970 --- /dev/null +++ b/api/iblrig.net.get_server_communicator.html @@ -0,0 +1,214 @@ + + + + + + + iblrig.net.get_server_communicator — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.get_server_communicator

+
+
+async iblrig.net.get_server_communicator(service_uri, name)[source]
+
+
Parameters:
+
+
+
Returns:
+

+

+
+
Parameters:
+

name (str)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.html b/api/iblrig.net.html new file mode 100644 index 000000000..0b82642df --- /dev/null +++ b/api/iblrig.net.html @@ -0,0 +1,265 @@ + + + + + + + iblrig.net — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net

+

Network communication between rigs.

+

An example of a remote_rigs.yaml file:

+

`yaml +neuropixel: '12.134.270.1' +'cameras:left': 'tcp://0.123.456.7:9998' +'cameras:right': 'tcp://0.123.456.6:9998' +tasks: 'udp://123.654.8.8' +`

+
+

Examples

+

Send a standard message (e.g. start) to all rigs and await their responses:

+
>>> responses = await services.start(exp_ref)
+
+
+

Send a standard message to all rigs without awaiting responses:

+
>>> for service in services.values():
+...     await service.init()
+
+
+

Send exp info message to all rigs and await their responses:

+
>>> responses = await self.services._signal(ExpMessage.EXPINFO, 'confirmed_send', [ExpMessage.EXPINFO, ...])
+
+
+

Send exp info message to all rigs without awaiting responses:

+
>>> for service in services.values():
+...     await service.confirmed_send([ExpMessage.EXPINFO, ...])
+
+
+

Request status from a single service (await echo):

+
>>> await services['cameras'].confirmed_send([ExpMessage.EXPSTATUS])
+
+
+

Send message to a single service without awaiting echo: +NB: use with causion: can cause infinite loops if both not correctly configured

+
>>> services['cameras'].send([ExpMessage.EXPSTATUS])
+
+
+
+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + +

check_uri_match

Log warning if URI in remote devices is wrong.

get_remote_devices

Return map of device name to network URI.

get_remote_devices_file

Return the location of the remote devices YAML file.

get_server_communicator

install_alyx_token

Save Alyx token sent from remote device.

read_stdin

Asynchronously reads lines from standard input.

update_alyx_token

Callback to update instance with Alyx token.

+

Classes

+ + + + + + + + + +

Auxiliaries

ExpInfo

A standard experiment information structure.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.install_alyx_token.html b/api/iblrig.net.install_alyx_token.html new file mode 100644 index 000000000..8f493a068 --- /dev/null +++ b/api/iblrig.net.install_alyx_token.html @@ -0,0 +1,212 @@ + + + + + + + iblrig.net.install_alyx_token — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.install_alyx_token

+
+
+iblrig.net.install_alyx_token(base_url, token)[source]
+

Save Alyx token sent from remote device.

+

Saves an Alyx token into the ONE params for a given database instance.

+
+
Parameters:
+
    +
  • base_url (str) – The Alyx database URL.

  • +
  • token (dict[str, dict]) – The token in the form {username: {‘token’: token}}.

  • +
+
+
Returns:
+

True if the token was far a user not already cached.

+
+
Return type:
+

bool

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.read_stdin.html b/api/iblrig.net.read_stdin.html new file mode 100644 index 000000000..f951c5238 --- /dev/null +++ b/api/iblrig.net.read_stdin.html @@ -0,0 +1,207 @@ + + + + + + + iblrig.net.read_stdin — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.read_stdin

+
+
+async iblrig.net.read_stdin(loop=None)[source]
+

Asynchronously reads lines from standard input.

+

Allows asynchronous reading of user keyboard input. Currently there is no cross-platform way to listen to +keypresses, but this function comes close.

+
+
Parameters:
+

loop (asyncio.AbstractEventLoop) – An optional event loop to use.

+
+
Yields:
+

str – A line of text from the standard input, if available.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.net.update_alyx_token.html b/api/iblrig.net.update_alyx_token.html new file mode 100644 index 000000000..65f670a3c --- /dev/null +++ b/api/iblrig.net.update_alyx_token.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.net.update_alyx_token — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.net.update_alyx_token

+
+
+iblrig.net.update_alyx_token(data, _, alyx=None, one=None)[source]
+

Callback to update instance with Alyx token.

+
+
Parameters:
+
    +
  • data ((str, dict)) – Tuple containing the Alyx database URL and token dict.

  • +
  • addr ((str, int)) – The address of the remote host that sent the Alyx data (unused).

  • +
  • alyx (one.webclient.AlyxClient) – An optional instance of Alyx to update with the token.

  • +
  • one.api.OneAlyx – An optional instance of ONE to update with the token.

  • +
+
+
Returns:
+

If True, the provided alyx or one instance was successfully updated with the token.

+
+
Return type:
+

bool

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.online_plots.DataModel.html b/api/iblrig.online_plots.DataModel.html new file mode 100644 index 000000000..1ec9014f2 --- /dev/null +++ b/api/iblrig.online_plots.DataModel.html @@ -0,0 +1,282 @@ + + + + + + + iblrig.online_plots.DataModel — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.online_plots.DataModel

+
Inheritance diagram of DataModel
+ + +
+

+
+
+
+class iblrig.online_plots.DataModel[source]
+

The data model is a pure numpy / pandas container for the choice world task. +It contains: +- a psychometrics dataframe that contains the count / choice and response time +per signed contrast and block contingency +- a last trials dataframe that contains 20 trials worth of data for the timeline view +- various counters such as ntrials and water delivered

+
+
+__init__(settings_file)[source]
+
+
Parameters:
+

settings_file (Path | None)

+
+
+
+ +
+
+compute_end_session_criteria()[source]
+

Implement critera to change the color of the figure display, according to the specifications of the task.

+
+ +
+
+update_trial(trial_data, bpod_data)[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+contrast_set = array([0.    , 0.0625, 0.125 , 0.25  , 0.5   , 1.    ])
+
+ +
+
+ntrials = 0
+
+ +
+
+ntrials_correct = 0
+
+ +
+
+ntrials_engaged = 0
+
+ +
+
+ntrials_nan = nan
+
+ +
+
+percent_correct = nan
+
+ +
+
+percent_error = nan
+
+ +
+
+probability_set = array([0.2, 0.5, 0.8])
+
+ +
+
+task_settings = None
+
+ +
+
+time_elapsed = 0.0
+
+ +
+
+water_delivered = 0.0
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.online_plots.OnlinePlots.html b/api/iblrig.online_plots.OnlinePlots.html new file mode 100644 index 000000000..dd35f5560 --- /dev/null +++ b/api/iblrig.online_plots.OnlinePlots.html @@ -0,0 +1,263 @@ + + + + + + + iblrig.online_plots.OnlinePlots — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.online_plots.OnlinePlots

+
Inheritance diagram of OnlinePlots
+ + +
+

+
+
+
+class iblrig.online_plots.OnlinePlots[source]
+

Full object to implement the online plots +Either the object is instantiated in a static mode from an existing jsonable file and it will produce the figure +>>> oplt = OnlinePlots(settings) +Or it can be instantiated empty, and then run on a file during acquisition. +Use ctrl + Z to interrupt +>>> OnlinePlots().run(jsonable_file)

+
+
+__init__(settings_file=None)[source]
+
+ +
+
+display_full_jsonable(jsonable_file)[source]
+
+
Parameters:
+

jsonable_file (Path | str)

+
+
+
+ +
+
+run(file_jsonable)[source]
+

Watch a jsonable file in conjunction with an iblrigv8 running task (for online use).

+
+
Parameters:
+

file_jsonable (Path or str) – The sessions jsonable file

+
+
Parameters:
+

file_jsonable (Path | str)

+
+
Return type:
+

None

+
+
+
+ +
+
+update_graphics(pupdate=None)[source]
+
+
Parameters:
+

pupdate (float | None)

+
+
+
+ +
+
+update_titles()[source]
+
+ +
+
+update_trial(trial_data, bpod_data)[source]
+

Update, both, the data model and the graphics for an upcoming trial.

+
+
Parameters:
+
    +
  • trial_data (pandas.DataFrame) – pandas record

  • +
  • bpod_data (dict) – doct interpreted from the bpod json dump

  • +
  • return:

  • +
+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.online_plots.html b/api/iblrig.online_plots.html new file mode 100644 index 000000000..2d12b465a --- /dev/null +++ b/api/iblrig.online_plots.html @@ -0,0 +1,194 @@ + + + + + + + iblrig.online_plots — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.online_plots

+

Classes

+ + + + + + + + + +

DataModel

The data model is a pure numpy / pandas container for the choice world task.

OnlinePlots

Full object to implement the online plots Either the object is instantiated in a static mode from an existing jsonable file and it will produce the figure >>> oplt = OnlinePlots(settings) Or it can be instantiated empty, and then run on a file during acquisition.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.create_bonsai_layout_from_template.html b/api/iblrig.path_helper.create_bonsai_layout_from_template.html new file mode 100644 index 000000000..4e95cee6f --- /dev/null +++ b/api/iblrig.path_helper.create_bonsai_layout_from_template.html @@ -0,0 +1,220 @@ + + + + + + + iblrig.path_helper.create_bonsai_layout_from_template — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.create_bonsai_layout_from_template

+
+
+iblrig.path_helper.create_bonsai_layout_from_template(workflow_file)[source]
+

Create a Bonsai layout file from a template if it does not already exist.

+

If the file with the suffix .bonsai.layout does not exist for the given +workflow file, this function will attempt to create it from a template +file with the suffix .bonsai.layout_template. If the template file also +does not exist, the function logs that no template layout is available.

+

Background: Bonsai stores dialog settings (window position, control +visibility, etc.) in an XML file with the suffix .bonsai.layout. These +layout files are user-specific and may be overwritten locally by the user +according to their preferences. To ensure that a default layout is +available, a template file with the suffix .bonsai.layout_template can +be provided as a starting point.

+
+
Parameters:
+

workflow_file (Path) – The path to the Bonsai workflow for which the layout is to be created.

+
+
Raises:
+

FileNotFoundError – If the provided workflow_file does not exist.

+
+
Parameters:
+

workflow_file (Path)

+
+
Return type:
+

None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.get_commit_hash.html b/api/iblrig.path_helper.get_commit_hash.html new file mode 100644 index 000000000..a64583dea --- /dev/null +++ b/api/iblrig.path_helper.get_commit_hash.html @@ -0,0 +1,200 @@ + + + + + + + iblrig.path_helper.get_commit_hash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.get_commit_hash

+
+
+iblrig.path_helper.get_commit_hash(folder)[source]
+
+
Parameters:
+

folder (str)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.get_local_and_remote_paths.html b/api/iblrig.path_helper.get_local_and_remote_paths.html new file mode 100644 index 000000000..28409a3b8 --- /dev/null +++ b/api/iblrig.path_helper.get_local_and_remote_paths.html @@ -0,0 +1,224 @@ + + + + + + + iblrig.path_helper.get_local_and_remote_paths — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.get_local_and_remote_paths

+
+
+iblrig.path_helper.get_local_and_remote_paths(local_path=None, remote_path=None, lab=None, iblrig_settings=None)[source]
+

Function used to parse input arguments to transfer commands.

+

If the arguments are None, reads in the settings and returns the values from the files. +local_subjects_path always has a fallback on the home directory / iblrig_data +remote_subjects_path has no fallback and will return None when all options are exhausted +:param local_path: +:param remote_path: +:param lab: +:param iblrig_settings: if provided, settings dictionary, otherwise will load the default settings files +:return: dictionary, with following keys (example output)

+
+
+
{‘local_data_folder’: PosixPath(‘C:/iblrigv8_data’),

‘remote_data_folder’: PosixPath(‘Y:/’), +‘local_subjects_folder’: PosixPath(‘C:/iblrigv8_data/mainenlab/Subjects’), +‘remote_subjects_folder’: PosixPath(‘Y:/Subjects’)}

+
+
+
+
+
Parameters:
+
    +
  • local_path (str | Path | None)

  • +
  • remote_path (str | Path | None)

  • +
  • lab (str | None)

  • +
+
+
Return type:
+

dict

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.html b/api/iblrig.path_helper.html new file mode 100644 index 000000000..4c066cad0 --- /dev/null +++ b/api/iblrig.path_helper.html @@ -0,0 +1,218 @@ + + + + + + + iblrig.path_helper — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

create_bonsai_layout_from_template

Create a Bonsai layout file from a template if it does not already exist.

get_commit_hash

get_local_and_remote_paths

Function used to parse input arguments to transfer commands.

iterate_collection

Given a session path returns the next numbered collection name.

iterate_previous_sessions

Iterate over the sessions of a given subject in both the remote and local path and search for a given protocol name.

load_pydantic_yaml

Load YAML data from a specified file or a standard IBLRIG settings file, validate it using a Pydantic model, and return the validated Pydantic model instance.

patch_settings

Update loaded settings files to ensure compatibility with latest version.

save_pydantic_yaml

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.iterate_collection.html b/api/iblrig.path_helper.iterate_collection.html new file mode 100644 index 000000000..6c7c99415 --- /dev/null +++ b/api/iblrig.path_helper.iterate_collection.html @@ -0,0 +1,226 @@ + + + + + + + iblrig.path_helper.iterate_collection — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.iterate_collection

+
+
+iblrig.path_helper.iterate_collection(session_path, collection_name='raw_task_data')[source]
+

Given a session path returns the next numbered collection name.

+
+
Parameters:
+
    +
  • session_path (str) – The session path containing zero or more numbered collections.

  • +
  • collection_name (str) – The collection name without the _NN suffix.

  • +
+
+
Returns:
+

The next numbered collection name.

+
+
Return type:
+

str

+
+
Parameters:
+

session_path (str)

+
+
+
+

Examples

+

In a folder where there are no raw task data folders

+
>>> iterate_collection('./subject/2020-01-01/001')
+'raw_task_data_00'
+
+
+

In a folder where there is one raw_imaging_data_00 folder

+
>>> iterate_collection('./subject/2020-01-01/001', collection_name='raw_imaging_data')
+'raw_imaging_data_01'
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.iterate_previous_sessions.html b/api/iblrig.path_helper.iterate_previous_sessions.html new file mode 100644 index 000000000..7090d2f2c --- /dev/null +++ b/api/iblrig.path_helper.iterate_previous_sessions.html @@ -0,0 +1,221 @@ + + + + + + + iblrig.path_helper.iterate_previous_sessions — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.iterate_previous_sessions

+
+
+iblrig.path_helper.iterate_previous_sessions(subject_name, task_name, n=1, **kwargs)[source]
+

Iterate over the sessions of a given subject in both the remote and local path and search for a given protocol name. +Return the information of the last n found matching protocols in the form of a dictionary.

+
+
Parameters:
+
    +
  • subject_name (str) – Name of the subject.

  • +
  • task_name (str) – Name of the protocol to look for in experiment description.

  • +
  • n (int, optional) – maximum number of protocols to return

  • +
  • **kwargs – Optional arguments to be passed to iblrig.path_helper.get_local_and_remote_paths +If not used, will use the arguments from iblrig/settings/iblrig_settings.yaml

  • +
+
+
Returns:
+

List of dictionaries with keys: session_path, experiment_description, task_settings, file_task_data

+
+
Return type:
+

list[dict]

+
+
Parameters:
+
    +
  • subject_name (str)

  • +
  • task_name (str)

  • +
  • n (int)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.load_pydantic_yaml.html b/api/iblrig.path_helper.load_pydantic_yaml.html new file mode 100644 index 000000000..af0b699d8 --- /dev/null +++ b/api/iblrig.path_helper.load_pydantic_yaml.html @@ -0,0 +1,232 @@ + + + + + + + iblrig.path_helper.load_pydantic_yaml — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.load_pydantic_yaml

+
+
+iblrig.path_helper.load_pydantic_yaml(model, filename=None, do_raise=True)[source]
+

Load YAML data from a specified file or a standard IBLRIG settings file, +validate it using a Pydantic model, and return the validated Pydantic model +instance.

+
+
Parameters:
+
    +
  • model (Type[T]) – The Pydantic model class to validate the YAML data against.

  • +
  • filename (Path | str | None, optional) – The path to the YAML file. +If None (default), the function deduces the appropriate standard IBLRIG +settings file based on the model.

  • +
  • do_raise (bool, optional) – If True (default), raise a ValidationError if validation fails. +If False, log the validation error and construct a model instance +with the provided data. Defaults to True.

  • +
+
+
Returns:
+

An instance of the Pydantic model, validated against the YAML data.

+
+
Return type:
+

T

+
+
Raises:
+
    +
  • ValidationError – If validation fails and do_raise is set to True. + The raised exception contains details about the validation error.

  • +
  • TypeError – If the filename is None and the model class is not recognized as + HardwareSettings or RigSettings.

  • +
+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.patch_settings.html b/api/iblrig.path_helper.patch_settings.html new file mode 100644 index 000000000..b766f447a --- /dev/null +++ b/api/iblrig.path_helper.patch_settings.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.path_helper.patch_settings — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.patch_settings

+
+
+iblrig.path_helper.patch_settings(rs, filename)[source]
+

Update loaded settings files to ensure compatibility with latest version.

+
+
Parameters:
+
    +
  • rs (dict) – A loaded settings file.

  • +
  • filename (str | Path) – The filename of the settings file.

  • +
+
+
Returns:
+

The updated settings.

+
+
Return type:
+

dict

+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.path_helper.save_pydantic_yaml.html b/api/iblrig.path_helper.save_pydantic_yaml.html new file mode 100644 index 000000000..02160b984 --- /dev/null +++ b/api/iblrig.path_helper.save_pydantic_yaml.html @@ -0,0 +1,206 @@ + + + + + + + iblrig.path_helper.save_pydantic_yaml — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.path_helper.save_pydantic_yaml

+
+
+iblrig.path_helper.save_pydantic_yaml(data, filename=None)[source]
+
+
Parameters:
+
    +
  • data (T)

  • +
  • filename (str | Path | None)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.BunchModel.html b/api/iblrig.pydantic_definitions.BunchModel.html new file mode 100644 index 000000000..db3dcfa9f --- /dev/null +++ b/api/iblrig.pydantic_definitions.BunchModel.html @@ -0,0 +1,249 @@ + + + + + + + iblrig.pydantic_definitions.BunchModel — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.BunchModel

+
Inheritance diagram of BunchModel
+ + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.BunchModel[source]
+
+
+items()[source]
+
+ +
+
+keys()[source]
+
+ +
+
+values()[source]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.ExistingFilePath.html b/api/iblrig.pydantic_definitions.ExistingFilePath.html new file mode 100644 index 000000000..7c2994e38 --- /dev/null +++ b/api/iblrig.pydantic_definitions.ExistingFilePath.html @@ -0,0 +1,204 @@ + + + + + + + iblrig.pydantic_definitions.ExistingFilePath — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.ExistingFilePath

+
+
+iblrig.pydantic_definitions.ExistingFilePath
+

Validate that path exists and is file. Cast to str upon save.

+

alias of Annotated[Path, PathType(path_type=file), PlainSerializer(func=~iblrig.pydantic_definitions., return_type=str, when_used=always)]

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettings.html b/api/iblrig.pydantic_definitions.HardwareSettings.html new file mode 100644 index 000000000..4a5b189ca --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettings.html @@ -0,0 +1,295 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettings — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettings

+
Inheritance diagram of HardwareSettings
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettings[source]
+
+
+MAIN_SYNC: bool
+
+ +
+
+RIG_NAME: str
+
+ +
+
+VERSION: str
+
+ +
+
+device_bpod: HardwareSettingsBpod
+
+ +
+
+device_cameras: dict[str, dict[str, HardwareSettingsCameraWorkflow | HardwareSettingsCamera]] | None
+
+ +
+
+device_frame2ttl: HardwareSettingsFrame2TTL
+
+ +
+
+device_microphone: HardwareSettingsMicrophone | None
+
+ +
+
+device_rotary_encoder: HardwareSettingsRotaryEncoder
+
+ +
+
+device_scale: HardwareSettingsScale
+
+ +
+
+device_screen: HardwareSettingsScreen
+
+ +
+
+device_sound: HardwareSettingsSound
+
+ +
+
+device_valve: HardwareSettingsValve
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'title': 'hardware_settings.yaml'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'MAIN_SYNC': FieldInfo(annotation=bool, required=True), 'RIG_NAME': FieldInfo(annotation=str, required=True), 'VERSION': FieldInfo(annotation=str, required=True), 'device_bpod': FieldInfo(annotation=HardwareSettingsBpod, required=True), 'device_cameras': FieldInfo(annotation=Union[dict[str, dict[str, Union[HardwareSettingsCameraWorkflow, HardwareSettingsCamera]]], NoneType], required=True), 'device_frame2ttl': FieldInfo(annotation=HardwareSettingsFrame2TTL, required=True), 'device_microphone': FieldInfo(annotation=Union[HardwareSettingsMicrophone, NoneType], required=False, default=None), 'device_rotary_encoder': FieldInfo(annotation=HardwareSettingsRotaryEncoder, required=True), 'device_scale': FieldInfo(annotation=HardwareSettingsScale, required=False, default=HardwareSettingsScale(COM_SCALE=None)), 'device_screen': FieldInfo(annotation=HardwareSettingsScreen, required=True), 'device_sound': FieldInfo(annotation=HardwareSettingsSound, required=True), 'device_valve': FieldInfo(annotation=HardwareSettingsValve, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsBpod.html b/api/iblrig.pydantic_definitions.HardwareSettingsBpod.html new file mode 100644 index 000000000..f65eb2bf7 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsBpod.html @@ -0,0 +1,265 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsBpod — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsBpod

+
Inheritance diagram of HardwareSettingsBpod
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsBpod[source]
+
+
+BPOD_TTL_TEST_DATE: date | None
+
+ +
+
+BPOD_TTL_TEST_STATUS: str | None
+
+ +
+
+COM_BPOD: str | None
+
+ +
+
+DISABLE_BEHAVIOR_INPUT_PORTS: list[Annotated[int, Ge(ge=1), Le(le=4)]]
+
+ +
+
+ROTARY_ENCODER_BPOD_PORT: Literal['Serial1', 'Serial2', 'Serial3', 'Serial4', 'Serial5', None]
+
+ +
+
+SOUND_BOARD_BPOD_PORT: Literal['Serial1', 'Serial2', 'Serial3', 'Serial4', 'Serial5', None]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'BPOD_TTL_TEST_DATE': FieldInfo(annotation=Union[date, NoneType], required=False, default=None), 'BPOD_TTL_TEST_STATUS': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'COM_BPOD': FieldInfo(annotation=Union[str, NoneType], required=True), 'DISABLE_BEHAVIOR_INPUT_PORTS': FieldInfo(annotation=list[Annotated[int, Ge, Le]], required=False, default=[2, 3, 4]), 'ROTARY_ENCODER_BPOD_PORT': FieldInfo(annotation=Literal['Serial1', 'Serial2', 'Serial3', 'Serial4', 'Serial5', None], required=False, default=None), 'SOUND_BOARD_BPOD_PORT': FieldInfo(annotation=Literal['Serial1', 'Serial2', 'Serial3', 'Serial4', 'Serial5', None], required=False, default=None)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsCamera.html b/api/iblrig.pydantic_definitions.HardwareSettingsCamera.html new file mode 100644 index 000000000..072c58bd8 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsCamera.html @@ -0,0 +1,260 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsCamera — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsCamera

+
Inheritance diagram of HardwareSettingsCamera
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsCamera[source]
+
+
+FPS: Annotated[int, Gt(gt=0)] | None
+
+ +
+
+HEIGHT: Annotated[int, Gt(gt=0)] | None
+
+ +
+
+INDEX: int
+
+ +
+
+SYNC_LABEL: str | None
+
+ +
+
+WIDTH: Annotated[int, Gt(gt=0)] | None
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'FPS': FieldInfo(annotation=Union[Annotated[int, Gt], NoneType], required=False, default=None, title='Camera frame rate', description='An optional frame rate (for camera QC only)'), 'HEIGHT': FieldInfo(annotation=Union[Annotated[int, Gt], NoneType], required=False, default=None, title='Camera frame height', description='An optional frame hight (for camera QC only)'), 'INDEX': FieldInfo(annotation=int, required=True), 'SYNC_LABEL': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, title='Camera DAQ sync label', description='The name of the DAQ channel wired to the camera GPIO'), 'WIDTH': FieldInfo(annotation=Union[Annotated[int, Gt], NoneType], required=False, default=None, title='Camera frame width', description='An optional frame width (for camera QC only)')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.html b/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.html new file mode 100644 index 000000000..5614cfd11 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.html @@ -0,0 +1,250 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow

+
Inheritance diagram of HardwareSettingsCameraWorkflow
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow[source]
+
+
+classmethod valid_path(v)[source]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'recording': FieldInfo(annotation=Path, required=True, title='Camera recording workflow', description='The path to the Bonsai workflow for camera recording.', metadata=[PathType(path_type='file'), PlainSerializer(func=<function <lambda>>, return_type=<class 'str'>, when_used='always')]), 'setup': FieldInfo(annotation=Union[Annotated[Path, PathType, PlainSerializer], NoneType], required=False, default=None, title='Optional camera setup workflow', description='An optional path to the camera setup Bonsai workflow.')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+recording: <lambda>, return_type=str, when_used=always)]
+
+ +
+
+setup: <lambda>, return_type=str, when_used=always)] | None
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.html b/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.html new file mode 100644 index 000000000..763bfe2c1 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.html @@ -0,0 +1,255 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsFrame2TTL — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsFrame2TTL

+
Inheritance diagram of HardwareSettingsFrame2TTL
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsFrame2TTL[source]
+
+
+COM_F2TTL: str | None
+
+ +
+
+F2TTL_CALIBRATION_DATE: date | None
+
+ +
+
+F2TTL_DARK_THRESH: int
+
+ +
+
+F2TTL_LIGHT_THRESH: int
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'COM_F2TTL': FieldInfo(annotation=Union[str, NoneType], required=True), 'F2TTL_CALIBRATION_DATE': FieldInfo(annotation=Union[date, NoneType], required=True), 'F2TTL_DARK_THRESH': FieldInfo(annotation=int, required=True), 'F2TTL_LIGHT_THRESH': FieldInfo(annotation=int, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.html b/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.html new file mode 100644 index 000000000..ab1252691 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.html @@ -0,0 +1,250 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsMicrophone — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsMicrophone

+
Inheritance diagram of HardwareSettingsMicrophone
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsMicrophone[source]
+
+
+serialize_path(bonsai_workflow, _info)[source]
+
+
Parameters:
+

bonsai_workflow (Path)

+
+
+
+ +
+
+BONSAI_WORKFLOW: Path
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'BONSAI_WORKFLOW': FieldInfo(annotation=Path, required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.html b/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.html new file mode 100644 index 000000000..0c348bccd --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.html @@ -0,0 +1,240 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder

+
Inheritance diagram of HardwareSettingsRotaryEncoder
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder[source]
+
+
+COM_ROTARY_ENCODER: str | None
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'COM_ROTARY_ENCODER': FieldInfo(annotation=Union[str, NoneType], required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsScale.html b/api/iblrig.pydantic_definitions.HardwareSettingsScale.html new file mode 100644 index 000000000..53514f2c4 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsScale.html @@ -0,0 +1,240 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsScale — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsScale

+
Inheritance diagram of HardwareSettingsScale
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsScale[source]
+
+
+COM_SCALE: str | None
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'COM_SCALE': FieldInfo(annotation=Union[str, NoneType], required=False, default=None)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsScreen.html b/api/iblrig.pydantic_definitions.HardwareSettingsScreen.html new file mode 100644 index 000000000..639be2ef4 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsScreen.html @@ -0,0 +1,265 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsScreen — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsScreen

+
Inheritance diagram of HardwareSettingsScreen
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsScreen[source]
+
+
+DISPLAY_IDX: int
+
+ +
+
+SCREEN_FREQ_TARGET: int
+
+ +
+
+SCREEN_FREQ_TEST_DATE: date | None
+
+ +
+
+SCREEN_FREQ_TEST_STATUS: str | None
+
+ +
+
+SCREEN_LUX_DATE: date | None
+
+ +
+
+SCREEN_LUX_VALUE: float | None
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'DISPLAY_IDX': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0), Le(le=1)]), 'SCREEN_FREQ_TARGET': FieldInfo(annotation=int, required=True, metadata=[Gt(gt=0)]), 'SCREEN_FREQ_TEST_DATE': FieldInfo(annotation=Union[date, NoneType], required=False, default=None), 'SCREEN_FREQ_TEST_STATUS': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'SCREEN_LUX_DATE': FieldInfo(annotation=Union[date, NoneType], required=False, default=None), 'SCREEN_LUX_VALUE': FieldInfo(annotation=Union[float, NoneType], required=False, default=None)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsSound.html b/api/iblrig.pydantic_definitions.HardwareSettingsSound.html new file mode 100644 index 000000000..0641e4932 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsSound.html @@ -0,0 +1,250 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsSound — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsSound

+
Inheritance diagram of HardwareSettingsSound
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsSound[source]
+
+
+AMP_TYPE: Literal['harp', 'AMP2X15'] | None
+
+ +
+
+COM_SOUND: str | None
+
+ +
+
+OUTPUT: Literal['harp', 'xonar', 'hifi', 'sysdefault']
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'AMP_TYPE': FieldInfo(annotation=Union[Literal['harp', 'AMP2X15'], NoneType], required=False, default=None), 'COM_SOUND': FieldInfo(annotation=Union[str, NoneType], required=False, default=None), 'OUTPUT': FieldInfo(annotation=Literal['harp', 'xonar', 'hifi', 'sysdefault'], required=True)}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.HardwareSettingsValve.html b/api/iblrig.pydantic_definitions.HardwareSettingsValve.html new file mode 100644 index 000000000..62ca5afa4 --- /dev/null +++ b/api/iblrig.pydantic_definitions.HardwareSettingsValve.html @@ -0,0 +1,265 @@ + + + + + + + iblrig.pydantic_definitions.HardwareSettingsValve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.HardwareSettingsValve

+
Inheritance diagram of HardwareSettingsValve
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.HardwareSettingsValve[source]
+
+
+FREE_REWARD_VOLUME_UL: Annotated[float, Gt(gt=0)]
+
+ +
+
+WATER_CALIBRATION_DATE: date
+
+ +
+
+WATER_CALIBRATION_N: Annotated[int, Gt(gt=0)]
+
+ +
+
+WATER_CALIBRATION_OPEN_TIMES: list[Annotated[float, Gt(gt=0)]]
+
+ +
+
+WATER_CALIBRATION_RANGE: list[Annotated[float, Gt(gt=0)]]
+
+ +
+
+WATER_CALIBRATION_WEIGHT_PERDROP: list[float]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'FREE_REWARD_VOLUME_UL': FieldInfo(annotation=float, required=False, default=1.5, metadata=[Gt(gt=0)]), 'WATER_CALIBRATION_DATE': FieldInfo(annotation=date, required=True), 'WATER_CALIBRATION_N': FieldInfo(annotation=int, required=False, default=5, metadata=[Ge(ge=3), Gt(gt=0)]), 'WATER_CALIBRATION_OPEN_TIMES': FieldInfo(annotation=list[Annotated[float, Gt]], required=True, metadata=[MinLen(min_length=2)]), 'WATER_CALIBRATION_RANGE': FieldInfo(annotation=list[Annotated[float, Gt]], required=True, metadata=[MinLen(min_length=2), MaxLen(max_length=2)]), 'WATER_CALIBRATION_WEIGHT_PERDROP': FieldInfo(annotation=list[float], required=False, default=typing.Annotated[float, Gt(gt=0)], metadata=[MinLen(min_length=2)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.RigSettings.html b/api/iblrig.pydantic_definitions.RigSettings.html new file mode 100644 index 000000000..5c0ba426f --- /dev/null +++ b/api/iblrig.pydantic_definitions.RigSettings.html @@ -0,0 +1,280 @@ + + + + + + + iblrig.pydantic_definitions.RigSettings — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.RigSettings

+
Inheritance diagram of RigSettings
+ + + + + + + + + +
+

+
+
+
+class iblrig.pydantic_definitions.RigSettings[source]
+
+
+classmethod str_must_not_contain_space(v)[source]
+
+ +
+
+classmethod validate_remote_data_path(v)[source]
+
+ +
+
+ALYX_LAB: str | None
+
+ +
+
+ALYX_URL: Url | None
+
+ +
+
+ALYX_USER: str | None
+
+ +
+
+iblrig_local_data_path: Path | None
+
+ +
+
+iblrig_local_subjects_path: Annotated[Path, PathType(path_type=dir)] | None
+
+ +
+
+iblrig_remote_data_path: Path | bool | None
+
+ +
+
+iblrig_remote_subjects_path: Path | None
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'title': 'iblrig_settings.yaml', 'validate_assignment': True}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'ALYX_LAB': FieldInfo(annotation=Union[str, NoneType], required=True, description="Your lab's name as registered on the Alyx database"), 'ALYX_URL': FieldInfo(annotation=Union[Url, NoneType], required=True, title='Alyx URL', description='The URL to your Alyx database'), 'ALYX_USER': FieldInfo(annotation=Union[str, NoneType], required=True, description='Your Alyx username'), 'iblrig_local_data_path': FieldInfo(annotation=Union[Path, NoneType], required=True, title='IBLRIG local data path', description='The local folder IBLRIG should use for storing data'), 'iblrig_local_subjects_path': FieldInfo(annotation=Union[Annotated[Path, PathType], NoneType], required=False, default=None, title='IBLRIG full local data path', description='An optional full local data folder (including /Subjects)'), 'iblrig_remote_data_path': FieldInfo(annotation=Union[Path, bool, NoneType], required=True, title='IBLRIG remote data path', description='The remote folder IBLRIG should use for storing data'), 'iblrig_remote_subjects_path': FieldInfo(annotation=Union[Path, NoneType], required=False, default=None, title='IBLRIG full remote data path', description='An optional full remote data folder (including /Subjects)')}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.TrialDataModel.html b/api/iblrig.pydantic_definitions.TrialDataModel.html new file mode 100644 index 000000000..2ff7fc614 --- /dev/null +++ b/api/iblrig.pydantic_definitions.TrialDataModel.html @@ -0,0 +1,254 @@ + + + + + + + iblrig.pydantic_definitions.TrialDataModel — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions.TrialDataModel

+
Inheritance diagram of TrialDataModel
+ + +
+

+
+
+
+class iblrig.pydantic_definitions.TrialDataModel[source]
+

A data model for trial data that extends BaseModel.

+

This model allows for the addition of extra fields beyond those defined in the model.

+
+
+classmethod preallocate_dataframe(n_rows)[source]
+

Preallocate a DataFrame with specified number of rows, using default values or pandas.NA.

+

This method creates a pandas DataFrame with the same columns as the fields defined in the Pydantic model. +Each column is initialized with the field’s default value if available, otherwise with pandas.NA.

+

We use Pandas.NA for default values rather than NaN, None or Zero. This allows us to clearly indicate missing +values - which will raise a Pydantic ValidationError.

+
+
Parameters:
+

n_rows (int) – The number of rows to create in the DataFrame.

+
+
Returns:
+

A DataFrame with n_rows rows and columns corresponding to the model’s fields.

+
+
Return type:
+

pd.DataFrame

+
+
Parameters:
+

n_rows (int)

+
+
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.pydantic_definitions.html b/api/iblrig.pydantic_definitions.html new file mode 100644 index 000000000..0db5f7db4 --- /dev/null +++ b/api/iblrig.pydantic_definitions.html @@ -0,0 +1,251 @@ + + + + + + + iblrig.pydantic_definitions — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.pydantic_definitions

+

Module Attributes

+ + + + + + +

ExistingFilePath

Validate that path exists and is file.

+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

BunchModel

HardwareSettings

HardwareSettingsBpod

HardwareSettingsCamera

HardwareSettingsCameraWorkflow

HardwareSettingsFrame2TTL

HardwareSettingsMicrophone

HardwareSettingsRotaryEncoder

HardwareSettingsScale

HardwareSettingsScreen

HardwareSettingsSound

HardwareSettingsValve

RigSettings

TrialDataModel

A data model for trial data that extends BaseModel.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.raw_data_loaders.html b/api/iblrig.raw_data_loaders.html new file mode 100644 index 000000000..dbb49c604 --- /dev/null +++ b/api/iblrig.raw_data_loaders.html @@ -0,0 +1,190 @@ + + + + + + + iblrig.raw_data_loaders — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.raw_data_loaders.load_task_jsonable.html b/api/iblrig.raw_data_loaders.load_task_jsonable.html new file mode 100644 index 000000000..c18980190 --- /dev/null +++ b/api/iblrig.raw_data_loaders.load_task_jsonable.html @@ -0,0 +1,214 @@ + + + + + + + iblrig.raw_data_loaders.load_task_jsonable — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.raw_data_loaders.load_task_jsonable

+
+
+iblrig.raw_data_loaders.load_task_jsonable(jsonable_file, offset=None)[source]
+

Reads in a task data jsonable file and returns a trials dataframe and a bpod data list.

+
+
Parameters:
+
    +
  • - jsonable_file (str) (full path to jsonable file.)

  • +
  • - offset (int or None) (The offset to start reading from (default: None).)

  • +
+
+
Returns:
+

- tuple

+
    +
  • trials_table (pandas.DataFrame): A DataFrame with the trial info in the same format as the Session trials table.

  • +
  • bpod_data (list): timing data for each trial

  • +
+

+
+
Return type:
+

A tuple containing:

+
+
Parameters:
+
    +
  • jsonable_file (str | Path)

  • +
  • offset (int | None)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.rig_component.RigComponent.html b/api/iblrig.rig_component.RigComponent.html new file mode 100644 index 000000000..8a6628f00 --- /dev/null +++ b/api/iblrig.rig_component.RigComponent.html @@ -0,0 +1,237 @@ + + + + + + + iblrig.rig_component.RigComponent — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.rig_component.RigComponent

+
Inheritance diagram of RigComponent
+ + + +
+

+
+
+
+class iblrig.rig_component.RigComponent[source]
+
+
+abstract property pretty_name: str
+

Get the component’s pretty name.

+
+
Returns:
+

A user-friendly name of the component.

+
+
Return type:
+

str

+
+
+
+ +
+
+abstract property settings: BaseModel
+

Get the component’s settings.

+
+
Returns:
+

The pydantic model for the component’s settings.

+
+
Return type:
+

BaseModel

+
+
+
+ +
+
+abstract property validator: Validator
+

Get the component’s validator.

+
+
Returns:
+

The validator instance associated with the component.

+
+
Return type:
+

Validator

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.rig_component.html b/api/iblrig.rig_component.html new file mode 100644 index 000000000..b88fca1b3 --- /dev/null +++ b/api/iblrig.rig_component.html @@ -0,0 +1,190 @@ + + + + + + + iblrig.rig_component — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.scale.Scale.html b/api/iblrig.scale.Scale.html new file mode 100644 index 000000000..077622ef9 --- /dev/null +++ b/api/iblrig.scale.Scale.html @@ -0,0 +1,290 @@ + + + + + + + iblrig.scale.Scale — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.scale.Scale

+
Inheritance diagram of Scale
+ + + + + +
+

+
+
+
+class iblrig.scale.Scale[source]
+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+assert_setting(query, expected_response=b'OK!', do_raise=True)[source]
+
+
Parameters:
+
    +
  • query (str)

  • +
  • expected_response (str)

  • +
  • do_raise (bool)

  • +
+
+
Return type:
+

bool

+
+
+
+ +
+
+get_grams()[source]
+

Obtain weight reading in grams and stability indicator.

+
+
Returns:
+

    +
  • float – Weight reading in grams

  • +
  • bool – Stability indicator: True if scale is stable, False if not

  • +
+

+
+
Return type:
+

tuple[float, bool]

+
+
+
+ +
+
+get_stable_grams()[source]
+

Blocking function that will only return a weight reading once the scale is stable.

+
+
Returns:
+

Stable weight reading (grams)

+
+
Return type:
+

float

+
+
+
+ +
+
+query_line(query)[source]
+
+
Parameters:
+

query (str)

+
+
Return type:
+

bytes

+
+
+
+ +
+
+tare()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+zero()[source]
+
+
Return type:
+

bool

+
+
+
+ +
+
+property grams: float
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.scale.ScaleData.html b/api/iblrig.scale.ScaleData.html new file mode 100644 index 000000000..2a3c5cb8b --- /dev/null +++ b/api/iblrig.scale.ScaleData.html @@ -0,0 +1,234 @@ + + + + + + + iblrig.scale.ScaleData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.scale.ScaleData

+
Inheritance diagram of ScaleData
+ + +
+

+
+
+
+class iblrig.scale.ScaleData[source]
+

ScaleData(weight: float = nan, unit: str = ‘g’, stable: bool = False, mode: str = ‘’)

+
+
+__init__(weight=nan, unit='g', stable=False, mode='')
+
+
Parameters:
+
+
+
Return type:
+

None

+
+
+
+ +
+
+mode: str = ''
+
+ +
+
+stable: bool = False
+
+ +
+
+unit: str = 'g'
+
+ +
+
+weight: float = nan
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.scale.html b/api/iblrig.scale.html new file mode 100644 index 000000000..177fd0ca6 --- /dev/null +++ b/api/iblrig.scale.html @@ -0,0 +1,194 @@ + + + + + + + iblrig.scale — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.serial_singleton.SerialSingleton.html b/api/iblrig.serial_singleton.SerialSingleton.html new file mode 100644 index 000000000..eb63ac97a --- /dev/null +++ b/api/iblrig.serial_singleton.SerialSingleton.html @@ -0,0 +1,380 @@ + + + + + + + iblrig.serial_singleton.SerialSingleton — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.serial_singleton.SerialSingleton

+
Inheritance diagram of SerialSingleton
+ + + + +
+

+
+
+
+class iblrig.serial_singleton.SerialSingleton[source]
+
+
+__init__(port=None, connect=True, **kwargs)[source]
+
+
Parameters:
+
    +
  • port (str | None)

  • +
  • connect (bool)

  • +
+
+
Return type:
+

None

+
+
+
+ +
+
+static __new__(cls, port=None, serial_number=None, *args, **kwargs)[source]
+
+
Parameters:
+
    +
  • port (str | None)

  • +
  • serial_number (str | None)

  • +
+
+
+
+ +
+
+close()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+open()[source]
+
+
Return type:
+

None

+
+
+
+ +
+
+query(query: Any, data_specifier: int = 1) bytes[source]
+
+query(query: Any, data_specifier: str) tuple[Any, ...]
+

Query data from the serial device.

+

This method is a combination of write() and read().

+
+
Parameters:
+
    +
  • query (Any) – Query to be sent to the serial device.

  • +
  • data_specifier (int or str, default: 1) – The number of bytes to receive from the serial device, or a format string +for unpacking.

    +

    When providing an integer, the specified number of bytes will be returned +as a bytestring. When providing a format string, the data will be +unpacked into a tuple accordingly. Format strings follow the conventions of +the struct module.

    +
  • +
+
+
Returns:
+

Data returned by the serial device. By default, data is formatted as a +bytestring. Alternatively, when provided with a format string, data will be +unpacked into a tuple according to the specified format string.

+
+
Return type:
+

bytes or tuple[Any]

+
+
+
+ +
+
+read(data_specifier: int = 1) bytes[source]
+
+read(data_specifier: str) tuple[Any, ...]
+

Read data from the serial device.

+
+
Parameters:
+

data_specifier (int or str, default: 1) – The number of bytes to receive from the serial device, or a format string +for unpacking.

+

When providing an integer, the specified number of bytes will be returned +as a bytestring. When providing a format string, the data will be +unpacked into a tuple accordingly. Format strings follow the conventions of +the struct module.

+
+
Returns:
+

Data returned by the serial device. By default, data is formatted as a +bytestring. Alternatively, when provided with a format string, data will +be unpacked into a tuple according to the specified format string.

+
+
Return type:
+

bytes or tuple[Any]

+
+
+
+ +
+
+static to_bytes(data)[source]
+

Convert data to bytestring.

+

This method extends serial.to_bytes() with support for NumPy types, +strings (interpreted as utf-8) and lists.

+
+
Parameters:
+

data (Any) – Data to be converted to bytestring.

+
+
Returns:
+

Data converted to bytestring.

+
+
Return type:
+

bytes

+
+
Parameters:
+

data (Any)

+
+
+
+ +
+
+write(data)[source]
+
+
Return type:
+

int | None

+
+
+
+ +
+
+write_packed(format_string, *data)[source]
+

Pack values according to format string and write to serial device.

+
+
Parameters:
+
+
+
Returns:
+

Number of bytes written to the serial device.

+
+
Return type:
+

int or None

+
+
Parameters:
+
    +
  • format_string (str)

  • +
  • data (Any)

  • +
+
+
+
+ +
+
+property port: str | None
+

Get the serial device’s communication port.

+
+
Returns:
+

The serial port (e.g., ‘COM3’, ‘/dev/ttyUSB0’) used by the serial device.

+
+
Return type:
+

str

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.serial_singleton.SerialSingletonException.html b/api/iblrig.serial_singleton.SerialSingletonException.html new file mode 100644 index 000000000..48829bf21 --- /dev/null +++ b/api/iblrig.serial_singleton.SerialSingletonException.html @@ -0,0 +1,202 @@ + + + + + + + iblrig.serial_singleton.SerialSingletonException — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.serial_singleton.SerialSingletonException

+
+
+exception iblrig.serial_singleton.SerialSingletonException[source]
+
+
+__init__(*args, **kwargs)
+
+ +
+
+__new__(**kwargs)
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.serial_singleton.filter_ports.html b/api/iblrig.serial_singleton.filter_ports.html new file mode 100644 index 000000000..39c85a276 --- /dev/null +++ b/api/iblrig.serial_singleton.filter_ports.html @@ -0,0 +1,235 @@ + + + + + + + iblrig.serial_singleton.filter_ports — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.serial_singleton.filter_ports

+
+
+iblrig.serial_singleton.filter_ports(**kwargs)[source]
+

Filter serial ports based on specified criteria.

+
+
Parameters:
+

**kwargs (keyword arguments) – Filtering criteria for serial ports. Each keyword should correspond +to an attribute of the serial port object (ListPortInfo). The values associated +with the keywords are used to filter the ports based on various conditions.

+
+
Yields:
+

str – The device name of a filtered serial port that meets all specified criteria.

+
+
Parameters:
+

kwargs (dict[str, Any])

+
+
Return type:
+

Generator[str, None, None]

+
+
+
+

Examples

+

To filter ports by manufacturer and product:

+
>>> for port in filter_ports(manufacturer="Arduino", product="Uno"):
+...     print(port)
+
+
+
+
+
Raises:
+

ValueError – If a specified attribute does not exist for a port.

+
+
Parameters:
+

kwargs (dict[str, Any])

+
+
Return type:
+

Generator[str, None, None]

+
+
+
+

Notes

+
    +
  • The function uses regular expressions for string matching when both actual +and expected values are strings.

  • +
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.serial_singleton.get_port_from_serial_number.html b/api/iblrig.serial_singleton.get_port_from_serial_number.html new file mode 100644 index 000000000..5057fc43e --- /dev/null +++ b/api/iblrig.serial_singleton.get_port_from_serial_number.html @@ -0,0 +1,209 @@ + + + + + + + iblrig.serial_singleton.get_port_from_serial_number — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.serial_singleton.get_port_from_serial_number

+
+
+iblrig.serial_singleton.get_port_from_serial_number(serial_number)[source]
+

Retrieve the com port of a USB serial device identified by its serial number.

+
+
Parameters:
+

serial_number (str) – The serial number of the USB device that you want to obtain the communication +port of.

+
+
Returns:
+

The communication port of the USB serial device that matches the serial number +provided by the user. The function will return None if no such device was found.

+
+
Return type:
+

str or None

+
+
Parameters:
+

serial_number (str)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.serial_singleton.get_serial_number_from_port.html b/api/iblrig.serial_singleton.get_serial_number_from_port.html new file mode 100644 index 000000000..80ee47986 --- /dev/null +++ b/api/iblrig.serial_singleton.get_serial_number_from_port.html @@ -0,0 +1,209 @@ + + + + + + + iblrig.serial_singleton.get_serial_number_from_port — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.serial_singleton.get_serial_number_from_port

+
+
+iblrig.serial_singleton.get_serial_number_from_port(port)[source]
+

Retrieve the serial number of a USB serial device identified by its com port.

+
+
Parameters:
+

port (str) – The communication port of the USB serial device for which you want to retrieve +the serial number.

+
+
Returns:
+

The serial number of the USB serial device corresponding to the provided +communication port. Returns None if no device matches the port.

+
+
Return type:
+

str or None

+
+
Parameters:
+

port (str | None)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.serial_singleton.html b/api/iblrig.serial_singleton.html new file mode 100644 index 000000000..0039f79f0 --- /dev/null +++ b/api/iblrig.serial_singleton.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.serial_singleton — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.serial_singleton

+

Functions

+ + + + + + + + + + + + +

filter_ports

Filter serial ports based on specified criteria.

get_port_from_serial_number

Retrieve the com port of a USB serial device identified by its serial number.

get_serial_number_from_port

Retrieve the serial number of a USB serial device identified by its com port.

+

Classes

+ + + + + + +

SerialSingleton

+

Exceptions

+ + + + + + +

SerialSingletonException

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.session_creator.draw_block_len.html b/api/iblrig.session_creator.draw_block_len.html new file mode 100644 index 000000000..2ffafa1d8 --- /dev/null +++ b/api/iblrig.session_creator.draw_block_len.html @@ -0,0 +1,190 @@ + + + + + + + iblrig.session_creator.draw_block_len — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.session_creator.draw_position.html b/api/iblrig.session_creator.draw_position.html new file mode 100644 index 000000000..ac85f3df8 --- /dev/null +++ b/api/iblrig.session_creator.draw_position.html @@ -0,0 +1,195 @@ + + + + + + + iblrig.session_creator.draw_position — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.session_creator.html b/api/iblrig.session_creator.html new file mode 100644 index 000000000..c1f421f38 --- /dev/null +++ b/api/iblrig.session_creator.html @@ -0,0 +1,199 @@ + + + + + + + iblrig.session_creator — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.session_creator

+

Creates sessions, pre-generates stim and ephys sessions.

+

Functions

+ + + + + + + + + + + + +

draw_block_len

draw_position

make_ephyscw_pc

Create positions, contrasts and block lengths for ephysCW.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.session_creator.make_ephyscw_pc.html b/api/iblrig.session_creator.make_ephyscw_pc.html new file mode 100644 index 000000000..3244fef7c --- /dev/null +++ b/api/iblrig.session_creator.make_ephyscw_pc.html @@ -0,0 +1,197 @@ + + + + + + + iblrig.session_creator.make_ephyscw_pc — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.session_creator.make_ephyscw_pc

+
+
+iblrig.session_creator.make_ephyscw_pc(prob_type='biased')[source]
+

Create positions, contrasts and block lengths for ephysCW.

+

Generates ~2000 trials.

+
+
Parameters:
+

prob_type (str) – ‘biased’: 0 contrast half has likely to be drawn, ‘uniform’: 0 contrast as likely as other contrasts

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.sound.configure_sound_card.html b/api/iblrig.sound.configure_sound_card.html new file mode 100644 index 000000000..4643f2a14 --- /dev/null +++ b/api/iblrig.sound.configure_sound_card.html @@ -0,0 +1,190 @@ + + + + + + + iblrig.sound.configure_sound_card — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.sound.format_sound.html b/api/iblrig.sound.format_sound.html new file mode 100644 index 000000000..bc0d0189f --- /dev/null +++ b/api/iblrig.sound.format_sound.html @@ -0,0 +1,201 @@ + + + + + + + iblrig.sound.format_sound — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.sound.format_sound

+
+
+iblrig.sound.format_sound(sound, file_path=None, flat=False)[source]
+

Format sound to send to sound card.

+

Binary files to be sent to the sound card need to be a single contiguous +vector of int32 s. 4 Bytes left speaker, 4 Bytes right speaker, …, etc.

+
+
Parameters:
+
    +
  • sound (2d numpy.array os shape (n_samples, 2)) – Stereo sound

  • +
  • file_path (str) – full path of file. [default: None]

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.sound.html b/api/iblrig.sound.html new file mode 100644 index 000000000..eb897db21 --- /dev/null +++ b/api/iblrig.sound.html @@ -0,0 +1,198 @@ + + + + + + + iblrig.sound — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.sound.make_sound.html b/api/iblrig.sound.make_sound.html new file mode 100644 index 000000000..6aa75dc14 --- /dev/null +++ b/api/iblrig.sound.make_sound.html @@ -0,0 +1,219 @@ + + + + + + + iblrig.sound.make_sound — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.sound.make_sound

+
+
+iblrig.sound.make_sound(rate=44100, frequency=5000, duration=0.1, amplitude=1, fade=0.01, chans='L+TTL')[source]
+

Build sounds and save bin file for upload to soundcard or play via +sounddevice lib.

+
+
Parameters:
+
    +
  • rate (int, optional) – sample rate of the soundcard use 96000 for Bpod, +defaults to 44100 for soundcard

  • +
  • frequency (int, optional) – (Hz) of the tone, if -1 will create uniform random white +noise, defaults to 10000

  • +
  • duration (float, optional) –

      +
    1. of sound, defaults to 0.1

    2. +
    +

  • +
  • amplitude (intor float, optional) – E[0, 1] of the sound 1=max 0=min, defaults to 1

  • +
  • fade (float, optional) –

      +
    1. time of fading window rise and decay, defaults to 0.01

    2. +
    +

  • +
  • chans (str, optional) – [‘mono’, ‘L’, ‘R’, ‘stereo’, ‘L+TTL’, ‘TTL+R’] number of +sound channels and type of output, defaults to ‘L+TTL’

  • +
+
+
Returns:
+

streo sound from mono definitions

+
+
Return type:
+

np.ndarray with shape (Nsamples, 2)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.ANSI.html b/api/iblrig.tools.ANSI.html new file mode 100644 index 000000000..2bdb496a5 --- /dev/null +++ b/api/iblrig.tools.ANSI.html @@ -0,0 +1,274 @@ + + + + + + + iblrig.tools.ANSI — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.ANSI

+
Inheritance diagram of ANSI
+ + +
+

+
+
+
+class iblrig.tools.ANSI[source]
+

ANSI Codes for formatting text on the CLI.

+
+
+__init__()
+
+
Return type:
+

None

+
+
+
+ +
+
+BLUE = '\x1b[94m'
+
+ +
+
+BOLD = '\x1b[1m'
+
+ +
+
+CYAN = '\x1b[96m'
+
+ +
+
+DARKCYAN = '\x1b[36m'
+
+ +
+
+DIM = '\x1b[2m'
+
+ +
+
+END = '\x1b[0m'
+
+ +
+
+GREEN = '\x1b[92m'
+
+ +
+
+PURPLE = '\x1b[95m'
+
+ +
+
+RED = '\x1b[91m'
+
+ +
+
+UNDERLINE = '\x1b[4m'
+
+ +
+
+WHITE = '\x1b[37m'
+
+ +
+
+YELLOW = '\x1b[93m'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.alyx_reachable.html b/api/iblrig.tools.alyx_reachable.html new file mode 100644 index 000000000..34d5c3f4f --- /dev/null +++ b/api/iblrig.tools.alyx_reachable.html @@ -0,0 +1,206 @@ + + + + + + + iblrig.tools.alyx_reachable — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.alyx_reachable

+
+
+iblrig.tools.alyx_reachable()[source]
+

Check if Alyx can be connected to.

+
+
Returns:
+

True if Alyx can be connected to, False otherwise.

+
+
Return type:
+

bool

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.ask_user.html b/api/iblrig.tools.ask_user.html new file mode 100644 index 000000000..7f432424f --- /dev/null +++ b/api/iblrig.tools.ask_user.html @@ -0,0 +1,224 @@ + + + + + + + iblrig.tools.ask_user — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.ask_user

+
+
+iblrig.tools.ask_user(prompt, default=False)[source]
+

Prompt the user for a yes/no response.

+

This function displays a prompt to the user and expects a yes or no response. +The response is not case-sensitive. If the user presses Enter without +typing anything, the function interprets it as the default response.

+
+
Parameters:
+
    +
  • prompt (str) – The prompt message to display to the user.

  • +
  • default (bool, optional) – The default response when the user presses Enter without typing +anything. If True, the default response is ‘yes’ (Y/y or Enter). +If False, the default response is ‘no’ (N/n or Enter).

  • +
+
+
Returns:
+

True if the user responds with ‘yes’ +False if the user responds with ‘no’

+
+
Return type:
+

bool

+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.call_bonsai.html b/api/iblrig.tools.call_bonsai.html new file mode 100644 index 000000000..dce07f23a --- /dev/null +++ b/api/iblrig.tools.call_bonsai.html @@ -0,0 +1,236 @@ + + + + + + + iblrig.tools.call_bonsai — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.call_bonsai

+
+
+iblrig.tools.call_bonsai(workflow_file, parameters=None, start=True, debug=False, bootstrap=True, editor=True, wait=True, check=False)[source]
+

Execute a Bonsai workflow within a subprocess call.

+
+
Parameters:
+
    +
  • workflow_file (str | Path) – Path to the Bonsai workflow file.

  • +
  • parameters (dict[str, str], optional) – Parameters to be passed to Bonsai workflow.

  • +
  • start (bool, optional) – Start execution of the workflow within Bonsai (default is True).

  • +
  • debug (bool, optional) – Enable debugging mode if True (default is False). +Only applies if editor is True.

  • +
  • bootstrap (bool, optional) – Enable Bonsai bootstrapping if True (default is True).

  • +
  • editor (bool, optional) – Enable Bonsai editor if True (default is True).

  • +
  • wait (bool, optional) – Wait for Bonsai process to finish (default is True).

  • +
  • check (bool, optional) – Raise CalledProcessError if Bonsai process exits with non-zero exit code (default is False). +Only applies if wait is True.

  • +
+
+
Returns:
+

Pointer to the Bonsai subprocess if wait is False, otherwise subprocess.CompletedProcess.

+
+
Return type:
+

Popen[bytes] | Popen[str | bytes | Any] | CompletedProcess

+
+
Raises:
+

FileNotFoundError – If the Bonsai executable does not exist. + If the specified workflow file does not exist.

+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.call_bonsai_async.html b/api/iblrig.tools.call_bonsai_async.html new file mode 100644 index 000000000..dbb98862e --- /dev/null +++ b/api/iblrig.tools.call_bonsai_async.html @@ -0,0 +1,231 @@ + + + + + + + iblrig.tools.call_bonsai_async — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.call_bonsai_async

+
+
+async iblrig.tools.call_bonsai_async(workflow_file, parameters=None, start=True, debug=False, bootstrap=True, editor=True)[source]
+

Asynchronously execute a Bonsai workflow within a subprocess call.

+
+
Parameters:
+
    +
  • workflow_file (str | Path) – Path to the Bonsai workflow file.

  • +
  • parameters (dict[str, str], optional) – Parameters to be passed to Bonsai workflow.

  • +
  • start (bool, optional) – Start execution of the workflow within Bonsai (default is True).

  • +
  • debug (bool, optional) – Enable debugging mode if True (default is False). +Only applies if editor is True.

  • +
  • bootstrap (bool, optional) – Enable Bonsai bootstrapping if True (default is True).

  • +
  • editor (bool, optional) – Enable Bonsai editor if True (default is True).

  • +
+
+
Returns:
+

Pointer to the Bonsai subprocess if wait is False, otherwise subprocess.CompletedProcess.

+
+
Return type:
+

asyncio.subprocess.Process

+
+
Raises:
+

FileNotFoundError – If the Bonsai executable does not exist. + If the specified workflow file does not exist.

+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.get_anydesk_id.html b/api/iblrig.tools.get_anydesk_id.html new file mode 100644 index 000000000..6454772b5 --- /dev/null +++ b/api/iblrig.tools.get_anydesk_id.html @@ -0,0 +1,235 @@ + + + + + + + iblrig.tools.get_anydesk_id — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.get_anydesk_id

+
+
+iblrig.tools.get_anydesk_id(format_id=True, silent=False)[source]
+

Retrieve the AnyDesk ID of the current machine.

+
+
Parameters:
+
    +
  • format_id (bool, optional) – If True (default), format the ID in blocks separated by spaces. +If False, return the ID as one continuous block.

  • +
  • silent (bool, optional) – If True, suppresses exceptions and logs them instead. +If False (default), raises exceptions.

  • +
+
+
Returns:
+

The AnyDesk ID as a formatted string (e.g., ‘123 456 789’) if successful, +or None on failure.

+
+
Return type:
+

str or None

+
+
Raises:
+
+
+
Parameters:
+
+
+
+
+

Notes

+

The function attempts to find the AnyDesk executable and retrieve the ID using the command line. +On success, the AnyDesk ID is returned as a formatted string. If silent is True, exceptions are logged, +and None is returned on failure. If silent is False, exceptions are raised on failure.

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.get_inheritors.html b/api/iblrig.tools.get_inheritors.html new file mode 100644 index 000000000..226310e0e --- /dev/null +++ b/api/iblrig.tools.get_inheritors.html @@ -0,0 +1,206 @@ + + + + + + + iblrig.tools.get_inheritors — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.get_inheritors

+
+
+iblrig.tools.get_inheritors(cls)[source]
+

Obtain a set of all direct inheritors of a class.

+
+
Parameters:
+

cls (T)

+
+
Return type:
+

set[T]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.get_lab_location_dict.html b/api/iblrig.tools.get_lab_location_dict.html new file mode 100644 index 000000000..eab449cae --- /dev/null +++ b/api/iblrig.tools.get_lab_location_dict.html @@ -0,0 +1,208 @@ + + + + + + + iblrig.tools.get_lab_location_dict — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.get_lab_location_dict

+
+
+iblrig.tools.get_lab_location_dict(hardware_settings, iblrig_settings)[source]
+
+
Parameters:
+
+
+
Return type:
+

dict[str, Any]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.html b/api/iblrig.tools.html new file mode 100644 index 000000000..9c166e475 --- /dev/null +++ b/api/iblrig.tools.html @@ -0,0 +1,231 @@ + + + + + + + iblrig.tools — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

alyx_reachable

Check if Alyx can be connected to.

ask_user

Prompt the user for a yes/no response.

call_bonsai

Execute a Bonsai workflow within a subprocess call.

call_bonsai_async

Asynchronously execute a Bonsai workflow within a subprocess call.

get_anydesk_id

Retrieve the AnyDesk ID of the current machine.

get_inheritors

Obtain a set of all direct inheritors of a class.

get_lab_location_dict

internet_available

Check if the internet connection is available.

static_vars

Decorator to add static variables to a function.

+

Classes

+ + + + + + +

ANSI

ANSI Codes for formatting text on the CLI.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.internet_available.html b/api/iblrig.tools.internet_available.html new file mode 100644 index 000000000..9368a48b0 --- /dev/null +++ b/api/iblrig.tools.internet_available.html @@ -0,0 +1,228 @@ + + + + + + + iblrig.tools.internet_available — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.internet_available

+
+
+iblrig.tools.internet_available(host='8.8.8.8', port=53, timeout=3, force_update=False)[source]
+

Check if the internet connection is available.

+

This function checks if an internet connection is available by attempting to +establish a connection to a specified host and port. It will use a cached +result if the latter is available and force_update is set to False.

+
+
Parameters:
+
    +
  • host (str, optional) – The IP address or domain name of the host to check the connection to. +Default is “8.8.8.8” (Google’s DNS server).

  • +
  • port (int, optional) – The port to use for the connection check. Default is 53 (DNS port).

  • +
  • timeout (int, optional) – The maximum time (in seconds) to wait for the connection attempt. +Default is 3 seconds.

  • +
  • force_update (bool, optional) – If True, force an update and recheck the internet connection even if +the result is cached. Default is False.

  • +
+
+
Returns:
+

True if an internet connection is available, False otherwise.

+
+
Return type:
+

bool

+
+
Parameters:
+
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.tools.static_vars.html b/api/iblrig.tools.static_vars.html new file mode 100644 index 000000000..04516fecb --- /dev/null +++ b/api/iblrig.tools.static_vars.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.tools.static_vars — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.tools.static_vars

+
+
+iblrig.tools.static_vars(**kwargs)[source]
+

Decorator to add static variables to a function.

+

This decorator allows you to add static variables to a function by providing +keyword arguments. Static variables are shared across all calls to the +decorated function.

+
+
Parameters:
+

**kwargs – Keyword arguments where the keys are variable names and the values are +the initial values of the static variables.

+
+
Returns:
+

A decorated function with the specified static variables.

+
+
Return type:
+

function

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.BehaviorCopier.html b/api/iblrig.transfer_experiments.BehaviorCopier.html new file mode 100644 index 000000000..24e648e62 --- /dev/null +++ b/api/iblrig.transfer_experiments.BehaviorCopier.html @@ -0,0 +1,233 @@ + + + + + + + iblrig.transfer_experiments.BehaviorCopier — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments.BehaviorCopier

+
Inheritance diagram of BehaviorCopier
+ + + +
+

+
+
+
+class iblrig.transfer_experiments.BehaviorCopier[source]
+
+
+finalize_copy(number_of_expected_devices=None)[source]
+

If main sync is bpod, expect a single stub file.

+
+ +
+
+assert_connect_on_init = False
+

Raise error if unable to write stub file to remote server.

+
+
Type:
+

bool

+
+
+
+ +
+
+property experiment_description
+
+ +
+
+tag = 'behavior'
+

The device name (adds this to the experiment description stub file on the remote server).

+
+
Type:
+

str

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.CopyState.html b/api/iblrig.transfer_experiments.CopyState.html new file mode 100644 index 000000000..de8d8bddc --- /dev/null +++ b/api/iblrig.transfer_experiments.CopyState.html @@ -0,0 +1,232 @@ + + + + + + + iblrig.transfer_experiments.CopyState — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments.CopyState

+
Inheritance diagram of CopyState
+ + + + +
+

+
+
+
+class iblrig.transfer_experiments.CopyState[source]
+

An enumeration.

+
+
+__new__(value)
+
+ +
+
+COMPLETE = 2
+
+ +
+
+FINALIZED = 3
+
+ +
+
+HARD_RESET = -1
+
+ +
+
+NOT_REGISTERED = 0
+
+ +
+
+PENDING = 1
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.EphysCopier.html b/api/iblrig.transfer_experiments.EphysCopier.html new file mode 100644 index 000000000..5d139b495 --- /dev/null +++ b/api/iblrig.transfer_experiments.EphysCopier.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.transfer_experiments.EphysCopier — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments.EphysCopier

+
Inheritance diagram of EphysCopier
+ + + +
+

+
+
+
+class iblrig.transfer_experiments.EphysCopier[source]
+
+
+initialize_experiment(acquisition_description=None, nprobes=None, main_sync=True, **kwargs)[source]
+
+ +
+
+assert_connect_on_init = True
+

Raise error if unable to write stub file to remote server.

+
+
Type:
+

bool

+
+
+
+ +
+
+tag = 'ephys'
+

The device name (adds this to the experiment description stub file on the remote server).

+
+
Type:
+

str

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.SessionCopier.html b/api/iblrig.transfer_experiments.SessionCopier.html new file mode 100644 index 000000000..8ab6969fa --- /dev/null +++ b/api/iblrig.transfer_experiments.SessionCopier.html @@ -0,0 +1,344 @@ + + + + + + + iblrig.transfer_experiments.SessionCopier — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments.SessionCopier

+
Inheritance diagram of SessionCopier
+ + +
+

+
+
+
+class iblrig.transfer_experiments.SessionCopier[source]
+

Initialize and copy session data to a remote server.

+
+
+__init__(session_path, remote_subjects_folder=None, tag=None)[source]
+

Initialize and copy session data to a remote server.

+
+
Parameters:
+
    +
  • session_path (str, pathlib.Path) – The partial or session path to copy.

  • +
  • remote_subjects_folder (str, pathlib.Path) – The remote server path to which to copy the session data.

  • +
  • tag (str) – The device name (adds this to the experiment description stub file on the remote server).

  • +
+
+
+
+ +
+
+copy_collections()[source]
+

Recursively copies the collection folders into the remote session path.

+

Do not overload, overload _copy_collections instead.

+
+ +
+
+copy_snapshots()[source]
+

Copy snapshots files from root session path.

+

Unlike the collection folders defined in the experiment description folder, the snapshots folder is optional and +may exist on multiple acquisition PCs. This method will copy any files over if the snapshots folder exists, +however it will fail if a file of the same name already exists. This ensures snapshots from multiple computers +don’t get overwritten.

+
+
Returns:
+

True if transfer successfully completed.

+
+
Return type:
+

bool

+
+
+
+ +
+
+finalize_copy(number_of_expected_devices=None)[source]
+

At the end of the copy, check if all the files are there and if so, aggregate the device files.

+
+ +
+
+get_state()[source]
+

Gets the current copier state.

+

State 0: this device experiment has not been initialized for this device +State 1: this device experiment is initialized (the experiment description stub is present on the remote) +State 2: this device experiment is copied on the remote server, but other devices copies are still pending +State 3: the whole experiment is finalized and all data is on the server +:return:

+
+
Return type:
+

tuple[CopyState | None, str]

+
+
+
+ +
+
+glob_file_remote_copy_status(status='*')[source]
+

status: pending / complete

+
+ +
+
+initialize_experiment(acquisition_description=None, overwrite=True)[source]
+

Copy acquisition description yaml to the server and local transfers folder.

+
+
Parameters:
+
    +
  • acquisition_description (dict) – The data to write to the experiment.description.yaml file.

  • +
  • overwrite (bool) – If true, overwrite any existing file with the new one, otherwise, update the existing file.

  • +
+
+
+
+ +
+
+run(number_of_expected_devices=None)[source]
+

Run the copy of this device experiment.

+

Will try to get as far as possible in the copy process (from states 0 init experiment to state 3 finalize experiment) +if possible, and return earlier if the process can’t be completed.

+
+ +
+
+assert_connect_on_init = True
+

Raise error if unable to write stub file to remote server.

+
+
Type:
+

bool

+
+
+
+ +
+
+property experiment_description
+
+ +
+
+property file_experiment_description
+

Returns the local experiment description file, if none found, returns one with the tag.

+
+ +
+
+property file_remote_experiment_description
+

Return the remote path to the remote stub file.

+
+ +
+
+property remote_experiment_description_stub
+
+ +
+
+property remote_session_path
+
+ +
+
+property state
+
+ +
+
+tag = 'fv-az1198-566_265527899354975'
+

The device name (adds this to the experiment description stub file on the remote server).

+
+
Type:
+

str

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.VideoCopier.html b/api/iblrig.transfer_experiments.VideoCopier.html new file mode 100644 index 000000000..e96cdfe76 --- /dev/null +++ b/api/iblrig.transfer_experiments.VideoCopier.html @@ -0,0 +1,258 @@ + + + + + + + iblrig.transfer_experiments.VideoCopier — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments.VideoCopier

+
Inheritance diagram of VideoCopier
+ + + +
+

+
+
+
+class iblrig.transfer_experiments.VideoCopier[source]
+
+
+static config2stub(config, collection='raw_video_data')[source]
+

Generate acquisition description stub from a camera config dict.

+
+
Parameters:
+
    +
  • config (dict) – A cameras configuration dictionary, found in device_cameras of hardware_settings.yaml.

  • +
  • collection (str) – The video output collection.

  • +
+
+
Returns:
+

An acquisition description file stub.

+
+
Return type:
+

dict

+
+
Parameters:
+
    +
  • config (dict)

  • +
  • collection (str)

  • +
+
+
+
+ +
+
+create_video_stub(config, collection='raw_video_data')[source]
+
+ +
+
+initialize_experiment(acquisition_description=None, **kwargs)[source]
+
+ +
+
+assert_connect_on_init = True
+

Raise error if unable to write stub file to remote server.

+
+
Type:
+

bool

+
+
+
+ +
+
+tag = 'video'
+

The device name (adds this to the experiment description stub file on the remote server).

+
+
Type:
+

str

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.copy_folders.html b/api/iblrig.transfer_experiments.copy_folders.html new file mode 100644 index 000000000..63f0ffd1d --- /dev/null +++ b/api/iblrig.transfer_experiments.copy_folders.html @@ -0,0 +1,219 @@ + + + + + + + iblrig.transfer_experiments.copy_folders — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments.copy_folders

+
+
+iblrig.transfer_experiments.copy_folders(local_folder, remote_folder, overwrite=False)[source]
+

Copy folders and files from a local location to a remote location.

+

This function copies all folders and files from a local directory to a +remote directory. It provides options to overwrite existing files in +the remote directory and ignore specific file patterns.

+
+
Parameters:
+
    +
  • local_folder (Path) – The path to the local folder to copy from.

  • +
  • remote_folder (Path) – The path to the remote folder to copy to.

  • +
  • overwrite (bool, optional) – If True, overwrite existing files in the remote folder. Default is False.

  • +
+
+
Returns:
+

True if the copying is successful, False otherwise.

+
+
Return type:
+

bool

+
+
Parameters:
+
    +
  • local_folder (Path)

  • +
  • remote_folder (Path)

  • +
  • overwrite (bool)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.transfer_experiments.html b/api/iblrig.transfer_experiments.html new file mode 100644 index 000000000..91cbe8d9e --- /dev/null +++ b/api/iblrig.transfer_experiments.html @@ -0,0 +1,215 @@ + + + + + + + iblrig.transfer_experiments — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.transfer_experiments

+

Functions

+ + + + + + +

copy_folders

Copy folders and files from a local location to a remote location.

+

Classes

+ + + + + + + + + + + + + + + + + + +

BehaviorCopier

CopyState

An enumeration.

EphysCopier

SessionCopier

Initialize and copy session data to a remote server.

VideoCopier

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.upgrade_iblrig.call_subprocesses.html b/api/iblrig.upgrade_iblrig.call_subprocesses.html new file mode 100644 index 000000000..bd5efe397 --- /dev/null +++ b/api/iblrig.upgrade_iblrig.call_subprocesses.html @@ -0,0 +1,214 @@ + + + + + + + iblrig.upgrade_iblrig.call_subprocesses — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.upgrade_iblrig.call_subprocesses

+
+
+iblrig.upgrade_iblrig.call_subprocesses(reset_repo=False, **kwargs)[source]
+

Perform upgrade-related subprocess calls.

+
+
Parameters:
+
    +
  • reset_repo (bool, optional) – If True, reset the local Git repository to its remote state before +upgrading.

  • +
  • **kwargs – Additional keyword arguments to be passed to subprocess calls.

  • +
+
+
Returns:
+

This function does not return any value.

+
+
Return type:
+

None

+
+
Raises:
+
+
+
Parameters:
+

reset_repo (bool)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.upgrade_iblrig.html b/api/iblrig.upgrade_iblrig.html new file mode 100644 index 000000000..865ed7780 --- /dev/null +++ b/api/iblrig.upgrade_iblrig.html @@ -0,0 +1,194 @@ + + + + + + + iblrig.upgrade_iblrig — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.upgrade_iblrig.upgrade.html b/api/iblrig.upgrade_iblrig.upgrade.html new file mode 100644 index 000000000..c91987c72 --- /dev/null +++ b/api/iblrig.upgrade_iblrig.upgrade.html @@ -0,0 +1,202 @@ + + + + + + + iblrig.upgrade_iblrig.upgrade — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.upgrade_iblrig.upgrade

+
+
+iblrig.upgrade_iblrig.upgrade(raise_exceptions=False, allow_reset=False)[source]
+

Upgrade the IBLRIG software installation.

+

This function upgrades the IBLRIG software installation to the latest +version available in the Git repository. It checks the local and remote +versions, confirms the upgrade with the user if necessary, and performs the +upgrade.

+
+
Parameters:
+
    +
  • raise_exceptions (bool)

  • +
  • allow_reset (bool)

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.valve.Valve.html b/api/iblrig.valve.Valve.html new file mode 100644 index 000000000..3a731d729 --- /dev/null +++ b/api/iblrig.valve.Valve.html @@ -0,0 +1,240 @@ + + + + + + + iblrig.valve.Valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.valve.Valve

+
Inheritance diagram of Valve
+ + +
+

+
+
+
+class iblrig.valve.Valve[source]
+
+
+__init__(settings)[source]
+
+
Parameters:
+

settings (HardwareSettingsValve)

+
+
+
+ +
+
+property calibration_date: date
+
+ +
+
+property calibration_range: list[float, float]
+
+ +
+
+property free_reward_time_sec: float
+
+ +
+
+property free_reward_volume_ul: float
+
+ +
+
+property is_calibrated: bool
+
+ +
+
+property new_calibration_open_times: set[float]
+
+ +
+
+property settings: HardwareSettingsValve
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.valve.ValveValues.html b/api/iblrig.valve.ValveValues.html new file mode 100644 index 000000000..1065857a2 --- /dev/null +++ b/api/iblrig.valve.ValveValues.html @@ -0,0 +1,267 @@ + + + + + + + iblrig.valve.ValveValues — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.valve.ValveValues

+
Inheritance diagram of ValveValues
+ + +
+

+
+
+
+class iblrig.valve.ValveValues[source]
+
+
+__init__(open_times_ms, weights_g)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+add_samples(open_times_ms, weights_g)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+clear_data()[source]
+
+ +
+
+ms2ul(time_ms)[source]
+
+
Parameters:
+

time_ms (Annotated[float, Ge(ge=0)] | Iterable[Annotated[float, Ge(ge=0)]])

+
+
Return type:
+

Annotated[float, Ge(ge=0)] | ndarray

+
+
+
+ +
+
+ul2ms(volume_ul)[source]
+
+
Parameters:
+

volume_ul (Annotated[float, Ge(ge=0)] | Iterable[Annotated[float, Ge(ge=0)]])

+
+
Return type:
+

Annotated[float, Ge(ge=0)] | ndarray

+
+
+
+ +
+
+property open_times_ms: ndarray
+
+ +
+
+property volumes_ul: ndarray
+
+ +
+
+property weights_g: ndarray
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.valve.html b/api/iblrig.valve.html new file mode 100644 index 000000000..6014c7599 --- /dev/null +++ b/api/iblrig.valve.html @@ -0,0 +1,194 @@ + + + + + + + iblrig.valve — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig.version_management.call_git.html b/api/iblrig.version_management.call_git.html new file mode 100644 index 000000000..9670e5b07 --- /dev/null +++ b/api/iblrig.version_management.call_git.html @@ -0,0 +1,232 @@ + + + + + + + iblrig.version_management.call_git — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.call_git

+
+
+iblrig.version_management.call_git(*args, cache_output=True, on_error='raise')[source]
+

Call a git command with the specified arguments.

+

This function executes a git command with the provided arguments. It can cache the output of the command +and handle errors based on the specified behavior.

+
+
Parameters:
+
    +
  • *args (str) – The arguments to pass to the git command.

  • +
  • cache_output (bool, optional) – Whether to cache the output of the command. Default is True.

  • +
  • on_error (str, optional) – The behavior when an error occurs. Either +- ‘raise’: raise the exception (default), +- ‘log’: log the exception, or +- ‘silence’: suppress the exception.

  • +
+
+
Returns:
+

The output of the git command as a string, or None if an error occurred.

+
+
Return type:
+

str or None

+
+
Raises:
+
    +
  • RuntimeError – If the installation is not managed through git and on_error is set to ‘raise’.

  • +
  • SubprocessError – If the command fails and on_error is set to ‘raise’.

  • +
+
+
Parameters:
+
    +
  • args (str)

  • +
  • cache_output (bool)

  • +
  • on_error (Literal['raise', 'log', 'silence'])

  • +
+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.check_for_updates.html b/api/iblrig.version_management.check_for_updates.html new file mode 100644 index 000000000..82212d3d3 --- /dev/null +++ b/api/iblrig.version_management.check_for_updates.html @@ -0,0 +1,215 @@ + + + + + + + iblrig.version_management.check_for_updates — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.check_for_updates

+
+
+iblrig.version_management.check_for_updates()[source]
+

Check for updates to the iblrig software.

+

This function compares the locally installed version of iblrig with the +latest available version to determine if an update is available.

+
+
Returns:
+

tuple[bool, Union[str, None]]

+
    +
  • A boolean indicating whether an update is available.

  • +
  • A string representing the latest available version, or None if +no remote version information is available.

  • +
+

+
+
Return type:
+

A tuple containing two elements.

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.check_upgrade_prerequisites.html b/api/iblrig.version_management.check_upgrade_prerequisites.html new file mode 100644 index 000000000..786d912cf --- /dev/null +++ b/api/iblrig.version_management.check_upgrade_prerequisites.html @@ -0,0 +1,227 @@ + + + + + + + iblrig.version_management.check_upgrade_prerequisites — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.check_upgrade_prerequisites

+
+
+iblrig.version_management.check_upgrade_prerequisites(exception_handler=None, *args, **kwargs)[source]
+

Check prerequisites for upgrading IBLRIG.

+

This function verifies the prerequisites necessary for upgrading IBLRIG. It checks for +internet connectivity, whether the IBLRIG installation is managed through Git, and +whether the script is running within the IBLRIG virtual environment.

+
+
Parameters:
+
    +
  • exception_handler (Callable, optional) – An optional callable that handles exceptions if raised during the check. +If provided, it will be called with the exception as the first argument, +followed by any additional positional arguments (*args), and any +additional keyword arguments (**kwargs).

  • +
  • *args (Additional positional arguments) – Any additional positional arguments needed by the exception_handler callable.

  • +
  • **kwargs (Additional keyword arguments) – Any additional keyword arguments needed by the exception_handler callable.

  • +
+
+
Raises:
+
    +
  • ConnectionError – If there is no connection to the internet.

  • +
  • RuntimeError – If the IBLRIG installation is not managed through Git, or + if the script is not running within the IBLRIG virtual environment.

  • +
+
+
Parameters:
+

exception_handler (Callable | None)

+
+
Return type:
+

None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_branch.html b/api/iblrig.version_management.get_branch.html new file mode 100644 index 000000000..b783bf1e1 --- /dev/null +++ b/api/iblrig.version_management.get_branch.html @@ -0,0 +1,207 @@ + + + + + + + iblrig.version_management.get_branch — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_branch

+
+
+iblrig.version_management.get_branch()[source]
+

Get the Git branch of the iblrig installation.

+
+
Returns:
+

The Git branch of the iblrig installation, or None if it cannot be determined.

+
+
Return type:
+

str or None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_changelog.html b/api/iblrig.version_management.get_changelog.html new file mode 100644 index 000000000..7812725e6 --- /dev/null +++ b/api/iblrig.version_management.get_changelog.html @@ -0,0 +1,216 @@ + + + + + + + iblrig.version_management.get_changelog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_changelog

+
+
+iblrig.version_management.get_changelog()[source]
+

Retrieve the changelog for the iblrig installation.

+

This function retrieves and caches the changelog for the iblrig installation +based on the current Git branch. If the changelog is already cached, it +returns the cached value. If not, it attempts to fetch the changelog from +the GitHub repository or read it locally if the remote fetch fails.

+
+
Returns:
+

The changelog for the iblrig installation.

+
+
Return type:
+

str

+
+
+
+

Notes

+

This method relies on the presence of a CHANGELOG.md file either in the +repository or locally.

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_commit_hash.html b/api/iblrig.version_management.get_commit_hash.html new file mode 100644 index 000000000..343b01ddb --- /dev/null +++ b/api/iblrig.version_management.get_commit_hash.html @@ -0,0 +1,213 @@ + + + + + + + iblrig.version_management.get_commit_hash — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_commit_hash

+
+
+iblrig.version_management.get_commit_hash(short=True)[source]
+

Get the hash of the currently checked out commit of the iblrig installation.

+
+
Parameters:
+

short (bool, optional) – Whether to return the short hash of the commit hash. Default is True.

+
+
Returns:
+

Hash of the currently checked out commit, or None if it cannot be determined.

+
+
Return type:
+

str or None

+
+
Parameters:
+

short (bool)

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_detailed_version_string.html b/api/iblrig.version_management.get_detailed_version_string.html new file mode 100644 index 000000000..008065af3 --- /dev/null +++ b/api/iblrig.version_management.get_detailed_version_string.html @@ -0,0 +1,223 @@ + + + + + + + iblrig.version_management.get_detailed_version_string — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_detailed_version_string

+
+
+iblrig.version_management.get_detailed_version_string(v_basic)[source]
+

Generate a detailed version string based on a basic version string.

+

This function takes a basic version string (major.minor.patch) and generates +a detailed version string by querying Git for additional version information. +The detailed version includes commit number of commits since the last tag, +and Git status (dirty or broken). It is designed to fail safely.

+
+
Parameters:
+

v_basic (str) – A basic version string in the format ‘major.minor.patch’.

+
+
Returns:
+

A detailed version string containing version information retrieved +from Git, or the original basic version string if Git information +cannot be obtained.

+
+
Return type:
+

str

+
+
Parameters:
+

v_basic (str)

+
+
+
+

Notes

+

This method will only work with installations managed through Git.

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_local_version.html b/api/iblrig.version_management.get_local_version.html new file mode 100644 index 000000000..3aff4f54b --- /dev/null +++ b/api/iblrig.version_management.get_local_version.html @@ -0,0 +1,211 @@ + + + + + + + iblrig.version_management.get_local_version — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_local_version

+
+
+iblrig.version_management.get_local_version()[source]
+

Parse the local version string to obtain a Version object.

+

This function attempts to parse the local version string (__version__) +and returns a Version object representing the parsed version. If the +parsing fails, it logs an error and returns None.

+
+
Returns:
+

A Version object representing the parsed local version, or None if +parsing fails.

+
+
Return type:
+

Union[version.Version, None]

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_remote_tags.html b/api/iblrig.version_management.get_remote_tags.html new file mode 100644 index 000000000..d889dc1fc --- /dev/null +++ b/api/iblrig.version_management.get_remote_tags.html @@ -0,0 +1,211 @@ + + + + + + + iblrig.version_management.get_remote_tags — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_remote_tags

+
+
+iblrig.version_management.get_remote_tags()[source]
+

Fetch remote Git tags if not already fetched.

+

This function fetches remote Git tags if they have not been fetched already. +If tags are already fetched, it does nothing. If the installation is not +managed through Git, it logs an error.

+
+
Return type:
+

None

+
+
+
+

Notes

+

This method will only work with installations managed through Git.

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.get_remote_version.html b/api/iblrig.version_management.get_remote_version.html new file mode 100644 index 000000000..30a3935b9 --- /dev/null +++ b/api/iblrig.version_management.get_remote_version.html @@ -0,0 +1,214 @@ + + + + + + + iblrig.version_management.get_remote_version — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.get_remote_version

+
+
+iblrig.version_management.get_remote_version()[source]
+

Retrieve the remote version of iblrig from the Git repository.

+

This function fetches and parses the remote version of the iblrig software +from the Git repository. It uses Git tags to identify available versions.

+
+
Returns:
+

A Version object representing the remote version if successfully obtained, +or None if the remote version cannot be retrieved.

+
+
Return type:
+

Union[version.Version, None]

+
+
+
+

Notes

+

This method will only work with installations managed through Git.

+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.html b/api/iblrig.version_management.html new file mode 100644 index 000000000..3fdc86ca1 --- /dev/null +++ b/api/iblrig.version_management.html @@ -0,0 +1,230 @@ + + + + + + + iblrig.version_management — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management

+

Functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

call_git

Call a git command with the specified arguments.

check_for_updates

Check for updates to the iblrig software.

check_upgrade_prerequisites

Check prerequisites for upgrading IBLRIG.

get_branch

Get the Git branch of the iblrig installation.

get_changelog

Retrieve the changelog for the iblrig installation.

get_commit_hash

Get the hash of the currently checked out commit of the iblrig installation.

get_detailed_version_string

Generate a detailed version string based on a basic version string.

get_local_version

Parse the local version string to obtain a Version object.

get_remote_tags

Fetch remote Git tags if not already fetched.

get_remote_version

Retrieve the remote version of iblrig from the Git repository.

is_dirty

Check if the Git working directory is dirty (has uncommitted changes).

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig.version_management.is_dirty.html b/api/iblrig.version_management.is_dirty.html new file mode 100644 index 000000000..4a69ad966 --- /dev/null +++ b/api/iblrig.version_management.is_dirty.html @@ -0,0 +1,208 @@ + + + + + + + iblrig.version_management.is_dirty — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig.version_management.is_dirty

+
+
+iblrig.version_management.is_dirty()[source]
+

Check if the Git working directory is dirty (has uncommitted changes).

+

Uses ‘git diff –quiet’ to determine if there are uncommitted changes in the Git repository.

+
+
Returns:
+

bool – False if the directory is clean (no uncommitted changes).

+
+
Return type:
+

True if the directory is dirty (has uncommitted changes) or an error occurs during execution,

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.html new file mode 100644 index 000000000..204398dd7 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_ImagingChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.html new file mode 100644 index 000000000..eb902ca62 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.html @@ -0,0 +1,212 @@ + + + + + + + iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session[source]
+
+
+static draw_quiescent_period()[source]
+

Draw the quiescent period.

+

For this task we double the quiescence period texp draw and remove the absolute offset of 200ms. +The resulting is a truncated exp distribution between 400ms and 1 sec

+

TODO: This is a broken overload and never actually called - quiescent periods are not changed from BiasedCW

+
+
Return type:
+

float

+
+
+
+ +
+
+protocol_name = '_iblrig_tasks_imagingChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.html new file mode 100644 index 000000000..636f11ec0 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.html @@ -0,0 +1,173 @@ + + + + + + + iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.html new file mode 100644 index 000000000..462326294 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_advancedChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.html new file mode 100644 index 000000000..6ef14f64d --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.html @@ -0,0 +1,243 @@ + + + + + + + iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session[source]
+

Advanced Choice World is the ChoiceWorld task using fixed 50/50 probability for the side +and contrasts defined in the parameters. +It differs from TrainingChoiceWorld in that it does not implement adaptive contrasts or debiasing, +and it differs from BiasedChoiceWorld in that it does not implement biased blocks.

+
+
+__init__(*args, contrast_set=[1.0, 0.5, 0.25, 0.125, 0.0625, 0.0, 0.0, 0.0625, 0.125, 0.25, 0.5, 1.0], probability_set=[1], reward_set_ul=[1.5], position_set=[-35, -35, -35, -35, -35, -35, 35, 35, 35, 35, 35, 35], stim_gain=4.0, stim_reverse=False, **kwargs)[source]
+
+
Parameters:
+
+
+
+
+ +
+
+draw_next_trial_info(**kwargs)[source]
+
+ +
+
+static extra_parser()[source]
+
+
Returns:
+

argparse.parser()

+
+
+
+ +
+
+next_trial()[source]
+
+ +
+
+protocol_name = '_iblrig_tasks_advancedChoiceWorld'
+
+ +
+
+property reward_amount
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.html new file mode 100644 index 000000000..7170946f5 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.html @@ -0,0 +1,173 @@ + + + + + + + iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.html new file mode 100644 index 000000000..a18b66eba --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_biasedChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.html new file mode 100644 index 000000000..d937a71a8 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.html @@ -0,0 +1,193 @@ + + + + + + + iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.html new file mode 100644 index 000000000..b62624335 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.html @@ -0,0 +1,173 @@ + + + + + + + iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.html new file mode 100644 index 000000000..e3a76f4c2 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_ephysChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig_tasks._iblrig_tasks_ephysChoiceWorld

+

Modules

+ + + + + + +

task

The ephys choice world task is the same as the biased choice world except that the trials are pregenerated and saved in a fixture file.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.html new file mode 100644 index 000000000..c47287458 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.html @@ -0,0 +1,235 @@ + + + + + + + iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session[source]
+
+
+__init__(*args, session_template_id=0, **kwargs)[source]
+
+ +
+
+static extra_parser()[source]
+
+
Returns:
+

argparse.parser()

+
+
+
+ +
+
+static get_session_template(session_template_id)[source]
+

Return the pre-generated trials dataframe from the 12 fixtures according to the template ID.

+
+
Parameters:
+

session_template_id (int) – Session template ID (0-11).

+
+
Parameters:
+

session_template_id (int)

+
+
Return type:
+

DataFrame

+
+
+
+ +
+
+next_trial()[source]
+
+ +
+
+protocol_name = '_iblrig_tasks_ephysChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.html new file mode 100644 index 000000000..d5389e1f2 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.html @@ -0,0 +1,175 @@ + + + + + + + iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task

+

The ephys choice world task is the same as the biased choice world except that +the trials are pregenerated and saved in a fixture file.

+

Classes

+ + + + + + +

Session

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.html new file mode 100644 index 000000000..bb228b542 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_habituationChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.html new file mode 100644 index 000000000..253ee75ce --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.html @@ -0,0 +1,192 @@ + + + + + + + iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session[source]
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.html new file mode 100644 index 000000000..04b69fe1f --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.html @@ -0,0 +1,173 @@ + + + + + + + iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.html new file mode 100644 index 000000000..d78a6f2aa --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.html b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.html new file mode 100644 index 000000000..1d4547a52 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.html @@ -0,0 +1,211 @@ + + + + + + + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData

+
Inheritance diagram of NeuroModulatorChoiceTrialData
+ + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData[source]
+
+
+choice_delay: Annotated[float, Ge(ge=0)]
+
+ +
+
+model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}
+

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

+
+ +
+
+model_config: ClassVar[ConfigDict] = {'extra': 'allow'}
+

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

+
+ +
+
+model_fields: ClassVar[Dict[str, FieldInfo]] = {'block_num': FieldInfo(annotation=int, required=False, default=0, metadata=[Ge(ge=0)]), 'block_trial_num': FieldInfo(annotation=int, required=False, default=0, metadata=[Ge(ge=0)]), 'choice_delay': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'contrast': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'omit_feedback': FieldInfo(annotation=bool, required=True), 'pause_duration': FieldInfo(annotation=float, required=False, default=0.0, metadata=[Ge(ge=0)]), 'position': FieldInfo(annotation=float, required=True), 'quiescent_period': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'response_side': FieldInfo(annotation=int, required=True, metadata=[Interval(gt=None, ge=-1, lt=None, le=1)]), 'response_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_amount': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'reward_valve_time': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_angle': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=-180.0, lt=None, le=180.0)]), 'stim_freq': FieldInfo(annotation=float, required=True, metadata=[Ge(ge=0)]), 'stim_gain': FieldInfo(annotation=float, required=True), 'stim_phase': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=6.283185307179586)]), 'stim_probability_left': FieldInfo(annotation=float, required=True, metadata=[Interval(gt=None, ge=0.0, lt=None, le=1.0)]), 'stim_reverse': FieldInfo(annotation=bool, required=True), 'stim_sigma': FieldInfo(annotation=float, required=True), 'trial_correct': FieldInfo(annotation=bool, required=True), 'trial_num': FieldInfo(annotation=int, required=True, metadata=[Ge(ge=0)])}
+

Metadata about the fields defined on the model, +mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

+

This replaces Model.__fields__ from Pydantic V1.

+
+ +
+
+omit_feedback: bool
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.html new file mode 100644 index 000000000..bf1918f60 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.html @@ -0,0 +1,229 @@ + + + + + + + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session[source]
+
+
+TrialDataModel
+

alias of NeuroModulatorChoiceTrialData

+
+ +
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+get_state_machine_trial(i)[source]
+
+ +
+
+next_trial()[source]
+
+ +
+
+property choice_to_feedback_delay
+
+ +
+
+property omit_feedback
+
+ +
+
+protocol_name = '_iblrig_tasks_neuromodulatorChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.html b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.html new file mode 100644 index 000000000..7c700953d --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.html @@ -0,0 +1,218 @@ + + + + + + + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks

+
Inheritance diagram of SessionRelatedBlocks
+ + + + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks[source]
+

In this scenario, the blocks define a poor and a rich side. +The probability blocks and reward blocks structure is staggered so that we explore all configurations every 4 blocks +P0 P1 P2 P1 P2 P1 P2 P1 P2 +R0 R1 R1 R2 R2 R1 R1 R2 R2

+
+
+__init__(*args, **kwargs)[source]
+
+ +
+
+draw_reward_amount()[source]
+
+ +
+
+new_block()[source]
+
+ +
+
+next_trial()[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.html new file mode 100644 index 000000000..631ef3923 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.html @@ -0,0 +1,179 @@ + + + + + + + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.html new file mode 100644 index 000000000..9cc5245e4 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_passiveChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.html new file mode 100644 index 000000000..ca25c67e1 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.html @@ -0,0 +1,234 @@ + + + + + + + iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session[source]
+
+
+__init__(*args, session_template_id=0, duration_spontaneous=600, skip_event_replay=False, **kwargs)[source]
+
+
Parameters:
+
    +
  • duration_spontaneous (int)

  • +
  • skip_event_replay (bool)

  • +
+
+
+
+ +
+
+static extra_parser()[source]
+
+
Returns:
+

argparse.parser()

+
+
+
+ +
+
+get_state_machine_trial(*args, **kwargs)[source]
+
+ +
+
+next_trial()[source]
+
+ +
+
+start_hardware()[source]
+
+ +
+
+protocol_name = '_iblrig_tasks_passiveChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.html new file mode 100644 index 000000000..53a841444 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.html @@ -0,0 +1,173 @@ + + + + + + + iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_spontaneous.html b/api/iblrig_tasks._iblrig_tasks_spontaneous.html new file mode 100644 index 000000000..9fa50acad --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_spontaneous.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_spontaneous — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.html b/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.html new file mode 100644 index 000000000..a0d7d6624 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.html @@ -0,0 +1,185 @@ + + + + + + + iblrig_tasks._iblrig_tasks_spontaneous.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_spontaneous.task.html b/api/iblrig_tasks._iblrig_tasks_spontaneous.task.html new file mode 100644 index 000000000..31d86cd40 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_spontaneous.task.html @@ -0,0 +1,175 @@ + + + + + + + iblrig_tasks._iblrig_tasks_spontaneous.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig_tasks._iblrig_tasks_spontaneous.task

+

The spontaneous protocol is used to record spontaneous activity in the mouse brain. +The task does nothing, only creates the architecture for the data streams to be recorded.

+

Classes

+ + + + + + +

Session

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.html new file mode 100644 index 000000000..831c2b1be --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.html new file mode 100644 index 000000000..7ccba94ba --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.html @@ -0,0 +1,203 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session[source]
+
+
+static extra_parser()[source]
+
+
Returns:
+

argparse.parser()

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.html b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.html new file mode 100644 index 000000000..340b61c7e --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.html @@ -0,0 +1,179 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none

+
+
+iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none(string)[source]
+
+
Parameters:
+

string (str)

+
+
Return type:
+

float | None

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.html new file mode 100644 index 000000000..32c647bc5 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.html @@ -0,0 +1,181 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.html b/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.html new file mode 100644 index 000000000..4f995eeca --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.html @@ -0,0 +1,172 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.html b/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.html new file mode 100644 index 000000000..e9ad130be --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.html @@ -0,0 +1,218 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+ +
+
+ +
+

iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session

+
Inheritance diagram of Session
+ + + + + + + + + + + + + + + + + + +
+

+
+
+
+class iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session[source]
+
+
+__init__(*args, training_level=0, debias=True, **kwargs)[source]
+
+ +
+
+check_training_phase()[source]
+
+ +
+
+static extra_parser()[source]
+
+
Returns:
+

argparse.parser()

+
+
+
+ +
+
+protocol_name = '_iblrig_tasks_trainingPhaseChoiceWorld'
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.html b/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.html new file mode 100644 index 000000000..c588ed482 --- /dev/null +++ b/api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.html @@ -0,0 +1,173 @@ + + + + + + + iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/iblrig_tasks.html b/api/iblrig_tasks.html new file mode 100644 index 000000000..d5a15807f --- /dev/null +++ b/api/iblrig_tasks.html @@ -0,0 +1,195 @@ + + + + + + + iblrig_tasks — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ + +
+
+
+
+ + + + \ No newline at end of file diff --git a/changelog.html b/changelog.html new file mode 100644 index 000000000..bd4f9f3df --- /dev/null +++ b/changelog.html @@ -0,0 +1,709 @@ + + + + + + + Changelog — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Changelog

+
+

8.24.1

+
    +
  • change UI workflow for appending a session

  • +
  • Video QC: changed log level from WARNING to INFO if less than 0.1% of frames have been dropped

  • +
  • Valve: Use restricted quadratic fit when converting reward volume to valve opening time

  • +
  • TrainingCW: add signed_contrast to trials_table definition

  • +
+
+
+

8.24.0

+
    +
  • feature: validate values in trials_table using Pydantic

  • +
  • feature: add auto-generated API reference to documentation

  • +
  • changed: show_trial_log() now accepts a dict for including additional log items

  • +
  • fix: _ephysChoiceWorld - values from the pre-generated sessions were not actually used

  • +
  • fix: _ephysChoiceWorld - trial fixtures contained inverted values for probability_left

  • +
  • fix: GUI - Subjects and Projects are not being cached

  • +
  • add script for validating audio output of Bpod HiFi Module (in scripts/ folder)

  • +
+
+
+
+

8.23.1

+
    +
  • feature: post hardware information to alyx

  • +
  • generate PDF documentation

  • +
  • increase verbosity of error handling in base task

  • +
  • remove dead code

  • +
+
+
+

8.23.0

+
    +
  • hardware validation: check for unexpected events on Bpod’s digital input ports

  • +
  • hardware validation: frame2ttl

  • +
+
+
+
+

8.22.1

+
    +
  • get past sessions bugfix when newer sessions are present only on the remote server

  • +
+
+
+

8.22.0

+
    +
  • add UI components for selecting remote devices

  • +
+
+
+
+

8.21.2

+
    +
  • fix: remote devices show as task parameters (regression)

  • +
+
+
+

8.21.1

+
    +
  • hotfix: add DISABLE_BEHAVIOR_INPUT_PORTS key to hardware_settings.yaml

  • +
+
+
+

8.21.0

+
    +
  • display values of automatically inferred task parameters

  • +
  • store pause durations to trial info

  • +
  • add backend for UDP communication between rig computers

  • +
  • use PDM for managing dependencies

  • +
  • log session call / commandline parameters to disk

  • +
  • fix: potential deadlock with SerialSingleton

  • +
  • fix: “galloping” valve during valve calibration

  • +
  • fix: values computed by “Get Training Phase” in “Tools” menu

  • +
  • fix: incorrect parsing of adaptive gain value in trainingChoiceWorld

  • +
+
+
+
+

8.20.0

+
    +
  • tab for displaying local sessions and their respective status

  • +
  • additional task parameters for passiveChoiceWorld

  • +
  • work on making the GUI code more modular

  • +
+
+
+
+

8.19.6

+
    +
  • hotfix: fix race-condition that caused scrambled online-plots

  • +
+
+
+

8.19.5

+
    +
  • hotfix: move serial validation from SerialSingleton to Serial

  • +
+
+
+

8.19.4

+
    +
  • hotfix: fix validation for Alyx when no Alyx URL has been set

  • +
  • hotfix: fix validation for Bpod HiFi module

  • +
  • adapted update instructions in update notification & documentation

  • +
+
+
+

8.19.3

+
    +
  • hotfix: force stimulus to freeze in center of screen during “freeze_reward” state

  • +
  • method for copying snapshots to the local server using the SessionCopier

  • +
  • documentation for transition to Bpod HiFi

  • +
+
+
+

8.19.2

+
    +
  • hotfix: only register water administrations once per protocol

  • +
  • hotfix: reverse wheel contingency now controlled through task parameter STIM_REVERSE

  • +
+
+
+

8.19.1

+
    +
  • hotfix: threading warnings during valve calibration (when used without scale)

  • +
  • hotfix: unreliable exit condition for state machine during valve calibration

  • +
+
+
+

8.19.0

+
    +
  • automated validation of rig components

  • +
  • adaptive reward parameter for trainingPhaseChoiceWorld

  • +
  • add validate_video entry-point

  • +
  • switch from flake8 to ruff for linting & code-checks

  • +
  • automatically set correct trigger-mode when setting up the cameras

  • +
  • support rotary encoder on arbitrary module port

  • +
  • add ambient sensor reading back to trial log

  • +
  • allow negative stimulus gain (reverse wheel contingency)

  • +
+
+
+
+

8.18.0

+
    +
  • valve calibration routine

  • +
+
+
+
+

8.17.0

+
    +
  • consolidated data transfer routine across all rig computers

  • +
  • new video workflow with support for multiple named camera setups

  • +
  • various small fixes, work on documentation, unit-tests

  • +
+
+
+
+

8.16.1

+
    +
  • Hoferlab: when bpod returns inconsistent error, time-out or correct, throw the exception after logging

  • +
  • add AMP_TYPE field to hardware_settings.yaml (device_sound) to handle the combination of HiFi module and AMP2x15 amplifier

  • +
+
+
+

8.16.0

+
    +
  • Support for Bpod HiFi Module

  • +
  • Support for Zapit Optostim (NM)

  • +
  • more robust handling of Bpod’s serial messages: iblrig.hardware._define_message

  • +
+
+
+
+

8.15.6

+
    +
  • Task specifications: The time from the stimulus offset to the quiescence period is targeted to 1 second instead of 1.5 seconds

  • +
  • Task specifications: The correct delay time starts running from the start of the reward state, not the end of the reward state.

  • +
  • Fixed unit-tests

  • +
+
+
+

8.15.5

+
    +
  • hotfix: show Garbor patch in passive choice-world, GUI option for session ID, no dud detection

  • +
+
+
+

8.15.4

+
    +
  • hotfix: disable prompt for deleting “duds” for appended sessions

  • +
+
+
+

8.15.3

+
    +
  • hotfix: don’t wait for microphone workflow to finish

  • +
+
+
+

8.15.2

+
    +
  • hotfix: pin iblutil to >=1.7.4 to address unicode encoding issue during logging

  • +
  • hotfix: allow pass with warning in case where lab validation fails due to Alyx down / server issues

  • +
  • change: use QT workers for Frame2TTL calibration steps

  • +
  • extra task parameters: support list of strings

  • +
  • frame2ttl: raise exception on incorrect port setting

  • +
  • convert_ui: add argument for filename glob

  • +
+
+
+

8.15.1

+
    +
  • hotfix: correct parsing of description files and ignore junk sessions in iterate_protocols

  • +
+
+
+

8.15.0

+
    +
  • feature: calibration routine for frame2ttl v1-3 in Tools menu

  • +
  • feature: debug-flag for IBLRIG Wizard

  • +
+
+
+
+

8.14.2

+
    +
  • hotfix: wrong return-type in _iterate_protocols - pt 2

  • +
+
+
+

8.14.1

+
    +
  • hotfix: wrong return-type in _iterate_protocols

  • +
+
+
+

8.14.0

+
    +
  • show dialog boxes and plots for appended sessions

  • +
+
+
+
+

8.13.5

+
    +
  • make sure unused arguments passed up to BaseChoiceWorld do not crash the task (example delay_secs in passiveChoiceWorld)

  • +
+
+
+

8.13.4

+
    +
  • pin iblutil to version 1.7.3 or later

  • +
  • reworked upgrade script and moved to separate file to avoid file-access issues

  • +
  • fixed display of version string in “about” tab

  • +
  • revert logging of task events to GUI only

  • +
+
+
+

8.13.3

+
    +
  • add tests with mock Bonsai to cover for task start methods

  • +
  • hotfix: also log to PowerShell (for now)

  • +
+
+
+

8.13.2

+
    +
  • hotfix: ‘WindowsPath’ object has no attribute ‘split’

  • +
+
+
+

8.13.1

+
    +
  • hotfix: passing non-existent parameter to Bonsai workflow

  • +
+
+
+

8.13.0

+
    +
  • restructured user interface

  • +
  • script for starting video-session in ephys-rig

  • +
  • installer scripts for Spinnaker SDK / PySpin

  • +
  • validated parsing of settings files

  • +
  • added legend to trials-timeline

  • +
  • added button for triggering a free reward (only available outside of running task for now)

  • +
  • cleaned-up logging

  • +
  • various improvements under the hood, clean-up and unit-tests

  • +
+
+
+
+

8.12.13

+
    +
  • fix problem with corrupt acquisition descriptions in history

  • +
+
+
+

8.12.12

+
    +
  • skipped

  • +
+
+
+

8.12.11

+
    +
  • hotfix for creation of bonsai layout-file

  • +
  • separated installers for Spinnaker SDK and PySpin

  • +
+
+
+

8.12.10

+
    +
  • ignore user-side changes to bonsai layouts (for camera workflows only)

  • +
  • error message if rig-name is not defined in Alyx

  • +
  • populate delegate users

  • +
  • the usual: minor fixes, clean-ups and unit-tests

  • +
+
+
+

8.12.9

+
    +
  • usability improvements for “Show Training Level” tool

  • +
  • ignore unused behavior ports

  • +
  • remove unnecessary dependencies

  • +
+
+
+

8.12.8

+
    +
  • fix incorrect limits & unit for adaptive gain in trainingChoiceWorld

  • +
  • usability improvements for “Show Training Level” tool

  • +
+
+
+

8.12.7

+
    +
  • online plot: fix line colors and add legends

  • +
  • do not show Bonsai editor during session

  • +
+
+
+

8.12.6

+
    +
  • reverting TTL on trial end introduced with PR #504, release 8.9.0

  • +
  • general code maintenance (unit-tests, doc-strings, type-hints, removal of dead code)

  • +
+
+
+

8.12.5

+
    +
  • add a tools menu in the wizard to get training level from v7 sessions to ease transition

  • +
+
+
+

8.12.4

+
    +
  • updated online-plots

  • +
+
+
+

8.12.3

+
    +
  • bugfix: getting training status of subject not present on local server

  • +
  • skipping of bpod initialization now optional (used in GUI)

  • +
  • disable button for status LED if not supported by hardware

  • +
  • tests, type-hints, removal of dead code

  • +
+
+
+

8.12.2

+
    +
  • bugfix: rollback skipping of bpod initialization (possible source of integer overflow)

  • +
  • removal of dead code

  • +
+
+
+

8.12.1

+
    +
  • bugfix: remember ability for setting the status LED

  • +
+
+
+

8.12.0

+
    +
  • add a trainingPhaseChoiceWorld task to fix the training levels

  • +
  • bugfix: copy script prompt accepts both upper case and lower case Y to proceed

  • +
  • bugfix: update-check used incorrect calls for subprocesses

  • +
+
+
+
+

8.11.5

+
    +
  • bugfix: negative time being displayed in the live-plots

  • +
+
+
+

8.11.4

+
    +
  • bugfix: incorrect subprocess-calls in version_management

  • +
+
+
+

8.11.3

+
    +
  • bugfix: 0 contrasts argument overwritten for trainingCW

  • +
+
+
+

8.11.2

+
    +
  • make custom_tasks optional

  • +
  • repair lost entry-point for iblrig wizard

  • +
  • fetch remote tags only if connected to internet

  • +
+
+
+

8.11.1

+
    +
  • add GUI options for AdvancedChoiceWorld

  • +
+
+
+

8.11.0

+
    +
  • add check for availability of internet

  • +
  • add proper CLI for data transfer scripts

  • +
  • add control for disabling Bpod status LED

  • +
  • skip initialization of existing Bpod singleton

  • +
  • remember settings for status LED and GUI position

  • +
  • move update-check to separate thread

  • +
  • detect duds (less than 42 trials) and offer deletion

  • +
  • various small bugfixes

  • +
+
+
+
+

8.10.2

+
    +
  • hot-fix parsing of path args in transfer_data

  • +
  • add install_spinnaker command for … installing spinnaker

  • +
  • fixed CI warnings about ports that haven’t been closed

  • +
  • draw subject weight for adaptive reward from previous session

  • +
  • format reward with 1 decimal on online plot

  • +
+
+
+

8.10.1

+
    +
  • more reliable way to check for dirty repository

  • +
  • add visual hint for unfilled list-views

  • +
+
+
+

8.10.0

+
    +
  • adaptive reward from previous sessions in TrainingChoiceWorld

  • +
  • updater: fetch remote changelog to advertise new features

  • +
+
+
+
+

8.9.4

+
    +
  • correction for version regex

  • +
  • fix version strings for compatibility with packaging.version

  • +
+
+
+

8.9.3

+
    +
  • re-implemented update notice

  • +
  • corrected implementation of end session criteria

  • +
  • set adaptive reward to false temporarily

  • +
+
+
+

8.9.2

+
    +
  • hot-fix for disabling the update-check - this will need work

  • +
+
+
+

8.9.1

+
    +
  • hot-fix for missing live-plots

  • +
+
+
+

8.9.0

+
    +
  • major rework of the GUI

  • +
  • allow pausing between trials

  • +
  • task-specific settings

  • +
  • new dialogs for weight & droppings

  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/faq.html b/faq.html new file mode 100644 index 000000000..e36ea286d --- /dev/null +++ b/faq.html @@ -0,0 +1,275 @@ + + + + + + + Frequently Asked Questions — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Frequently Asked Questions

+

Here we collect common issues and questions regarding IBLRIG.

+
+

First Aid

+

If your rig is acting up:

+
    +
  • Employ the automated test-script bundled with IBLRIG. This script helps identify common configuration issues. +Execute it using PowerShell:

    +
    C:\iblrigv8\venv\scripts\Activate.ps1
    +validate_iblrig
    +
    +
    +
  • +
  • Check the comprehensive user manual (“Appendix 3” on GoogleDrive). +Verify if all connections are secure, and configurations align with the manual’s guidelines.

  • +
  • Don’t hesitate to contact our developer team for assistance. We’re committed to getting your system back on track.

  • +
+
+
+

Bug Reports & Feature Requests

+

IBLRIG remains in dynamic development. Your input is invaluable in shaping its direction. Send us your +bug reports and feature-requests via GitHub - we will do our best to help you.

+
+
+

Sound Issues

+
    +
  • Double-check all wiring for loose connections.

  • +
  • Is hardware_settings.yaml set up correctly? Valid options for sound OUTPUT are:

    +
      +
    • hifi,

    • +
    • harp,

    • +
    • xonar, or

    • +
    • sysdefault.

    • +
    +

    Make sure that this value matches the actual soundcard used on your rig. +Note that sysdefault is only used in test scenarios and should not be used during actual experiments.

    +
  • +
+
+
+

Screen Issues

+
+

General

+
    +
  • The ribbon cable attaching the screen to the driver board is notoriously finicky. If you are having brightness issues or do not have a signal, try gently repositioning this cable and ensure it is tightly seated in its connection.

  • +
  • Screen and ribbon cable can be easily damaged. It is useful to have backup at hand.

  • +
  • Screen flashing can occur if the power supply does not match the screen specifications. Use a 12V adapter with at least 1A.

  • +
  • If the Bonsai display is appearing on the PC screen when a task starts, try unplugging the rig screen, rebooting and plugging the screen back in. Other variations of screen unplugging and rebooting may also work. +Also make sure, that the DISPLAY_IDX value in hardware_settings.yaml is set correctly.

  • +
+
+
+

Defining Default Position & Size of Bonsai Visualizers

+

Is the preview window of the video recording showing on the iPad screen instead of the computer’s main display during a +session? To redefine the default position and size of the Bonsai visualizer:

+
    +
  1. Open the Bonsai executable distributed with IBLRIG: C:\iblrigv8\Bonsai\Bonsai.exe.

  2. +
  3. Open the respective Bonsai workflow:

    +
    C:\iblrigv8\devices\camera_recordings\TrainingRig_SaveVideo_TrainingTasks.bonsai
    +
    +
    +
  4. +
  5. Start the workflow by clicking on the play-button.

  6. +
  7. Adjust the position and size of the windows as per your preference.

  8. +
  9. Stop the workflow.

  10. +
  11. Save the workflow.

  12. +
+
+
+
+

Camera Issues

+
    +
  • If a camera is not detected by the computer or causes intermittent issues it might be an issue with the USB connection.

    +
      +
    • Ensure that the camera is connected to the computer on a USB3 port (usually indicated by a blue plastic tab in the port). +USB2 (black tabs) neither provides the necessary transfer rates nor sufficient current to power the camera.

    • +
    • Use the original USB3.1 cable provided by FLIR. +It comes in 3 m or 5 m - stick with the shorter version if possible.

    • +
    • Try to avoid USB extensions. +The original cable (see above) should be sufficiently long in most situations.

    • +
    • Ideally, use one of the onboard USB3 ports of your computer facing to the back of the machine. +Front-facing ports may not be able to provide enough power.

    • +
    • If you use a USB 3.1 Host Controller Card check if it requires additional powering through a SATA or Molex cable. +FLIR offers a few models that should work fine.

    • +
    +
  • +
+
+
+

Frame2TTL

+
    +
  • Version 1 of Frame2TTL won’t be detected after restarting the computer. +Unplugging and replugging the USB cable should make it responsive again.

  • +
  • If IBLRIG complains about not receiving any TTL signals from Frame2TTL:

    +
      +
    • Ensure Frame2TTL’s sensor is positioned over the bottom-right corner of the rig’s screen. +Secure the sensor’s cable to the screen mount with a zip-tie to prevent it from slipping off the screen. +Additionally, use a piece of electrical tape to hold the sensor in place.

    • +
    • Verify that the sensor is connected to Frame2TTL with the correct polarity

      +
        +
      • Version 1: GND = black cable, SIG = white cable

      • +
      • Version 2 and 3: BLK = black cable, WHT = white cable

      • +
      +
    • +
    • Ensure that Frame2TTL’s TTL Output is plugged into Bpod’s TTL Input #1. +Note that versions 2 and 3 of Frame2TTL have a second BNC output labeled “analog” - this is not the TTL output.

    • +
    • Recalibrate Frame2TTL using the calibration routine in IBLRIG’s Tools menu and check for any errors.

    • +
    +
  • +
  • If the above steps do not resolve the issue, try the following:

    +
      +
    1. Swap out the BNC cable between Frame2TTL and Bpod. +Use a single cable without any branches.

    2. +
    3. Connect an oscilloscope to the Bpod end of the cable and run a calibration. +Look for a voltage step in Frame2TTL’s output when the calibration routine switches from dark to light.

    4. +
    5. If you do see the change in the TTL signal, the Bpod might be faulty. Try using a different Bpod unit.

    6. +
    7. If you do not see the voltage step, the Frame2TTL might be faulty. Try using a different Frame2TTL unit.

    8. +
    +
  • +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/genindex.html b/genindex.html new file mode 100644 index 000000000..7ba2cca9b --- /dev/null +++ b/genindex.html @@ -0,0 +1,3015 @@ + + + + + + Index — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ _ + | A + | B + | C + | D + | E + | F + | G + | H + | I + | K + | L + | M + | N + | O + | P + | Q + | R + | S + | T + | U + | V + | W + | Y + | Z + +
+

_

+ + + +
+ +

A

+ + + +
+ +

B

+ + + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

E

+ + + +
+ +

F

+ + + +
+ +

G

+ + + +
+ +

H

+ + + +
+ +

I

+ + + +
    +
  • + iblrig + +
  • +
  • + iblrig.base_choice_world + +
  • +
  • + iblrig.base_tasks + +
  • +
  • + iblrig.choiceworld + +
  • +
  • + iblrig.commands + +
  • +
  • + iblrig.constants + +
  • +
  • + iblrig.ephys + +
  • +
  • + iblrig.frame2ttl + +
  • +
  • + iblrig.graphic + +
  • +
  • + iblrig.gui + +
  • +
  • + iblrig.gui.frame2ttl + +
  • +
  • + iblrig.gui.resources_rc + +
  • +
  • + iblrig.gui.splash + +
  • +
  • + iblrig.gui.tab_about + +
  • +
  • + iblrig.gui.tab_data + +
  • +
  • + iblrig.gui.tab_docs + +
  • +
  • + iblrig.gui.tab_log + +
  • +
  • + iblrig.gui.tools + +
  • +
  • + iblrig.gui.ui_frame2ttl + +
  • +
  • + iblrig.gui.ui_login + +
  • +
  • + iblrig.gui.ui_splash + +
  • +
  • + iblrig.gui.ui_tab_about + +
  • +
  • + iblrig.gui.ui_tab_data + +
  • +
  • + iblrig.gui.ui_tab_docs + +
  • +
  • + iblrig.gui.ui_tab_log + +
  • +
  • + iblrig.gui.ui_tab_session + +
  • +
  • + iblrig.gui.ui_update + +
  • +
  • + iblrig.gui.ui_validation + +
  • +
  • + iblrig.gui.ui_valve + +
  • +
  • + iblrig.gui.ui_wizard + +
  • +
  • + iblrig.gui.validation + +
  • +
  • + iblrig.gui.valve + +
  • +
  • + iblrig.gui.wizard + +
  • +
  • + iblrig.hardware + +
  • +
  • + iblrig.hardware_validation + +
  • +
  • + iblrig.hifi + +
  • +
  • + iblrig.misc + +
  • +
  • + iblrig.net + +
  • +
  • + iblrig.online_plots + +
  • +
  • + iblrig.path_helper + +
  • +
  • + iblrig.pydantic_definitions + +
  • +
  • + iblrig.raw_data_loaders + +
  • +
  • + iblrig.rig_component + +
  • +
  • + iblrig.scale + +
  • +
  • + iblrig.serial_singleton + +
  • +
  • + iblrig.session_creator + +
  • +
  • + iblrig.sound + +
  • +
+ +

K

+ + + +
+ +

L

+ + + +
+ +

M

+ + + +
+ +

N

+ + + +
+ +

O

+ + + +
+ +

P

+ + + +
+ +

Q

+ + + +
+ +

R

+ + + +
+ +

S

+ + + +
+ +

T

+ + + +
+ +

U

+ + + +
+ +

V

+ + + +
+ +

W

+ + + +
+ +

Y

+ + +
+ +

Z

+ + +
+ + + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/hardware.html b/hardware.html new file mode 100644 index 000000000..f562e95f9 --- /dev/null +++ b/hardware.html @@ -0,0 +1,246 @@ + + + + + + + Hardware Guide — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Hardware Guide

+
+

Upgrading Xonar AE to Bpod HiFi Module

+
+

Note

+

The following guide only concerns behavior rigs using Asus Xonar AE sound cards. +The Harp sound cards used in our Ephys and Mesoscope rigs work fine and do not require replacing!

+
+
+

Background

+

In their original design, IBL’s behavioral training rigs relied on a consumer-grade sound-card - the ASUS Xonar AE - for delivering auditory cues to the subject. We have identified the Xonar AE as a weak point in the design of the training rig as this choice of hardware has several severe drawbacks:

+
    +
  • Synchronization between individual components of the rig relies on TTL Signals, a standardized way of communicating between digital devices. +With the Xonar sound-card, we emulate TTL pulses on one of the soundcard’s analog audio outputs. +The resulting signal does not conform well to the TTL standard since (a) we cannot guarantee the required signal rise-times, and (b) pulse-amplitude depends on the computer’s audio volume and impedance settings. The effects are increased latencies and accidental misconfigurations. +The latter have the potential to cause synchronization issues and more problems further down the pipeline.

  • +
  • The ASUS Xonar AE does not seem to be a particularly robust piece of equipment - we’ve experienced several catastrophic failures across our rigs at IBL. Replacement hardware is increasingly hard to come by as the Asus Xonar AE is not being produced anymore.

  • +
  • The soundcard’s driver has been causing issues with specific Windows updates that require manual intervention / rollback of the respective updates.

  • +
  • There is no Windows 11 specific driver available.

  • +
+

For these reasons, we decided to replace the Xonar AE with the Bpod HiFi Module HD by Sanworks: +The HiFi Module is capable of delivering high fidelity sound stimuli at low latencies, supports proper TTL signaling as well as serial communication with the Bpod Finite State Machine and does not require any dedicated drivers. +The upgrade procedure is straightforward and should take no longer than 5-10 minutes.

+
+
+

Requirements

+

To replace your existing Xonar AE with the Bpod HiFi Module HD you will require the following:

+
    +
  • 1x Bpod HiFi Module HD

  • +
  • 1x Micro-USB to USB-A cable

  • +
  • 1x Ethernet cable (RJ45)

  • +
  • 1x RCA to 3.5 mm audio adapter

  • +
  • 1x 3 mm flathead screwdriver

  • +
+
+

Warning

+

Support for the Bpod HiFi Module was introduced with IBLRIG 8.16.0 and will not be backported to older version of IBLRIG. +Make sure to upgrade to the latest version of IBLRIG before continuing with this guide.

+
+
+
+

Upgrade Procedure

+
    +
  1. Use the 3 mm flathead screwdriver to unscrew the BNC to wire adapter from the amplifier board. +While the adapter itself is not needed anymore we will continue using the BNC cable. +Leave the other end of the BNC cable plugged into the Bpod as it is.

    +
    +_images/amp2x15_labels.png +
    +

    Disconnect the BNC to wire adapter from the amplifier board.

    +
    +
    +
  2. +
  3. Unplug the 3.5 mm audio cable from the Xonar AE sound card on the backside of the rig’s computer. +Leave the other end of the 3.5 mm audio cable connected to the amplifier board.

    +
    +_images/xonar_labels.png +
    +

    Unplug the 3.5 mm audio cable from the Xonar AE sound card.

    +
    +
    +
  4. +
  5. Connect the Bpod HiFi Module as follows:

    +
      +
    • the BNC cable connects to TTL In 2 of the Bpod (cf. step 1),

    • +
    • the 3.5 mm audio cable connects to the amplifier board via the RCA adapter (cf. step 2),

    • +
    • the USB cable connects to the rig’s computer

    • +
    • the Ethernet cable connects to one of the Bpod’s Module ports. +Warning: Bpod uses identical connectors for its Behavior ports - do not mix them up!

    • +
    +
    +_images/hifi_labels.png +
    +

    The Bpod HiFi Modules and its connections.

    +
    +
    +
  6. +
  7. Open C:/iblrigv8/settings/hardware_settings.yaml in a text-editor. +Find the section device_sound and adapt it as follows:

    +
    device_sound:
    +  OUTPUT: hifi
    +  COM_SOUND: COMx  # replace with the HiFi Module's actual COM port!
    +  AMP_TYPE: AMP2X15
    +
    +
    +
    +

    Tip

    +

    Use Windows’ device manager to identify the HiFi Module’s COM port. +The device should show up in the section labelled “Ports (COM & LPT)” after plugging it in.

    +
    +
  8. +
  9. Start IBLRIG and make sure that the hardware validation during start-up does not find any issues. +Finally, start a session and verify that you can hear the audio cues.

  10. +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 000000000..beb5d97c8 --- /dev/null +++ b/index.html @@ -0,0 +1,167 @@ + + + + + + + IBLRIG — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+
+

IBLRIG

+

Welcome to the International Brain Laboratory’s decision-making task implementation.

+

The task is implemented using the Bpod Finite State Machine (SanWorks) and uses Bonsai visual programming language (on Windows) for the visual stimuli and Python for all other purposes.

+ +
+
+
+
+
+
+
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/installation.html b/installation.html new file mode 100644 index 000000000..28b719ed1 --- /dev/null +++ b/installation.html @@ -0,0 +1,370 @@ + + + + + + + Installation guide — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Installation guide

+
+

Prerequisites

+
    +
  • A computer running Windows 10 or 11,

  • +
  • A working installation of git for windows, and

  • +
  • Notepad++ or some other decent text editor.

  • +
+
+
+

Tip

+

iblrigv8 can be installed alongside older versions of iblrig without affecting the latter.

+
+
+

Tip

+

If you believe this guide is incomplete or requires improvements, please don’t hesitate to reach out and +submit a bug report.

+
+
+

Preparing Windows PowerShell

+

Open Windows PowerShell in administrator mode:

+
    +
  • Click on the Windows Start button or press the Windows key on your keyboard.

  • +
  • Type “PowerShell” into the search bar.

  • +
  • You should see “Windows PowerShell” or “PowerShell” in the search results.

  • +
  • Right-click on it.

  • +
  • In the context menu that appears, select “Run as administrator.”

  • +
+

Now, run the following command at the prompt of Windows PowerShell:

+
Set-ExecutionPolicy RemoteSigned -Force
+
+
+
+

Tip

+

Keep the Administrator PowerShell open for the next step.

+
+
+

Background

+

In PowerShell, there are execution policies that determine the level of security for running scripts. The default execution +policy is often set to Restricted, which means that scripts are not allowed to run. However, to install Python or run +certain scripts, you need to adjust the execution policy. By setting the execution policy to RemoteSigned, you are +allowing the execution of locally created scripts without any digital signature while requiring that remotely downloaded +scripts (from the internet) must be digitally signed by a trusted source to run. This strikes a balance between security +and usability.

+
+
+
+

Installing Visual C++ Redistributable

+

With the Administrator PowerShell still open, run the following commands:

+
New-Item -ItemType Directory -Force -Path C:\Temp
+Invoke-WebRequest -Uri https://download.microsoft.com/download/1/6/B/16B06F60-3B20-4FF2-B699-5E9B7962F9AE/VSU_4/vcredist_x64.exe  -OutFile C:\Temp\vcredist_x64.exe
+Start-Process -NoNewWindow -Wait -FilePath C:\Temp\vcredist_x64.exe -ArgumentList "/install", "/quiet", "/norestart"
+Invoke-WebRequest -Uri https://aka.ms/vs/17/release/vc_redist.x64.exe  -OutFile C:\Temp\vc_redist.x64.exe
+Start-Process -NoNewWindow -Wait -FilePath C:\Temp\vc_redist.x64.exe -ArgumentList "/install", "/quiet", "/norestart"
+
+
+
+

Warning

+

Make sure you exit the Administrator PowerShell before continuing with the next steps!

+
+
+

Background

+

These commands will create a temporary directory, download and install the Visual C++ Redistributable package for +64-bit Windows systems. The installer is retrieved from a Microsoft server and executed with parameters to ensure a seamless +and unobtrusive installation process.

+
+
+
+

Installing Python 3.10

+

Open a new Windows Powershell prompt (no administrator mode) and run the following:

+
New-Item -ItemType Directory -Force -Path C:\Temp
+Invoke-WebRequest -Uri https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe -OutFile C:\Temp\python-3.10.11-amd64.exe
+Start-Process -NoNewWindow -Wait -FilePath C:\Temp\python-3.10.11-amd64.exe -ArgumentList "/passive", "InstallAllUsers=0", "Include_launcher=0", "Include_test=0"
+
+
+

Check that everything worked by running the following command:

+
&$env:UserProfile\AppData\Local\Programs\Python\Python310\python.exe --version
+
+
+

The command should return Python 3.10.11

+
+

Background

+

These commands will create a temporary directory, download the Python installer from a specific URL, and then execute the +installer with specific installation options, all in a controlled and automated manner.

+
+
+
+

Installing iblrigv8

+
    +
  1. From the Powershell command line, clone the iblrigv8 branch of iblrig to C:\iblrigv8:

    +
    git clone -b iblrigv8 https://github.com/int-brain-lab/iblrig.git C:\iblrigv8
    +
    +
    +
  2. +
  3. Install a new virtual environment and update pip:

    +
    &$env:UserProfile\AppData\Local\Programs\Python\Python310\python.exe -m venv C:\iblrigv8\venv
    +C:\iblrigv8\venv\scripts\python.exe -m pip install --upgrade pip wheel
    +
    +
    +
  4. +
  5. Install iblrig in editable mode:

    +
    C:\iblrigv8\venv\scripts\Activate.ps1
    +cd C:\iblrigv8
    +pip install -e .
    +
    +
    +
  6. +
  7. Install Spinnaker SDK and PySpin:

    +
    install_spinnaker
    +install_pyspin
    +
    +
    +
  8. +
  9. Install Bonsai in portable mode:

    +
    cd C:\iblrigv8\Bonsai
    +powershell.exe .\install.ps1
    +cd ..
    +
    +
    +
  10. +
  11. Install additional tasks and extractors for personal projects (optional):

    +
    git clone https://github.com/int-brain-lab/project_extraction.git C:\project_extraction
    +cd C:\project_extraction
    +pip install -e .
    +
    +
    +
  12. +
  13. Continue with the next section.

  14. +
+
+
+

Configuration Instructions

+
+

Rig Configuration Files

+

Copy the template settings files:

+
cd C:\iblrigv8\settings
+cp hardware_settings_template.yaml hardware_settings.yaml
+cp iblrig_settings_template.yaml iblrig_settings.yaml
+explorer C:\iblrigv8\settings
+
+
+

Update the two settings files using a text-editor:

+
    +
  • iblrig_settings.yaml

  • +
  • hardware_settings.yaml

  • +
+

If the computer has been used with IBLRIG version 7 or earlier, the correct values can likely be found in C:\iblrig_params\ +.iblrig_params.json.

+
+
+

Setting up ONE

+

Setup ONE to connect to https://alyx.internationalbrainlab.org, you will need your Alyx username and password.

+

See instructions for that here: https://int-brain-lab.github.io/iblenv/notebooks_external/one_quickstart.html

+
+

Make sure you can connect to Alyx !

+

Open a Python shell in the environment and connect to Alyx (you may have to setup ONE)

+
C:\iblrigv8\venv\scripts\Activate.ps1
+ipython
+
+
+

Then at the IPython prompt

+
from one.api import ONE
+one = ONE(username='your_username', password='your_password', base_url='https://alyx.internationalbrainlab.org')
+
+
+
+
+

You can check that everything went fine by running the test suite:

+
cd C:\iblrigv8
+python -m unittest discover
+
+
+

The tests should pass to completion after around 40 seconds

+
+
+
+
+

Updating iblrigv8

+

To update iblrigv8 to the newest version:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+cd C:\iblrigv8
+git pull
+pip install --upgrade -e .
+
+
+

To update the additional tasks and extractors (see Installing iblrigv8, point 5):

+
cd C:\project_extraction
+git pull
+
+
+
+

Tip

+

While usually quite snappy, upgrading the virtual environment in some instances can take longer than expected. +Please be patient during the upgrade procedure.

+
+
+
+

Switch to specific iblrig version

+
+

Warning

+

Downgrading is not recommended and may not work as some releases break compatibility with earlier versions.

+
+

First fetch all available version tags and list them:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+cd C:\iblrigv8
+git fetch --all --tags --prune
+git tag --list '8.*'
+
+
+

Then switch to the desired version, for example 8.15.5:

+
git checkout tag/8.15.5
+pip install --upgrade -e .
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 000000000..87e60794e Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 000000000..5f70fe913 --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,516 @@ + + + + + + Python Module Index — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ i +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ i
+ iblrig +
    + iblrig.base_choice_world +
    + iblrig.base_tasks +
    + iblrig.choiceworld +
    + iblrig.commands +
    + iblrig.constants +
    + iblrig.ephys +
    + iblrig.frame2ttl +
    + iblrig.graphic +
    + iblrig.gui +
    + iblrig.gui.frame2ttl +
    + iblrig.gui.resources_rc +
    + iblrig.gui.splash +
    + iblrig.gui.tab_about +
    + iblrig.gui.tab_data +
    + iblrig.gui.tab_docs +
    + iblrig.gui.tab_log +
    + iblrig.gui.tools +
    + iblrig.gui.ui_frame2ttl +
    + iblrig.gui.ui_login +
    + iblrig.gui.ui_splash +
    + iblrig.gui.ui_tab_about +
    + iblrig.gui.ui_tab_data +
    + iblrig.gui.ui_tab_docs +
    + iblrig.gui.ui_tab_log +
    + iblrig.gui.ui_tab_session +
    + iblrig.gui.ui_update +
    + iblrig.gui.ui_validation +
    + iblrig.gui.ui_valve +
    + iblrig.gui.ui_wizard +
    + iblrig.gui.validation +
    + iblrig.gui.valve +
    + iblrig.gui.wizard +
    + iblrig.hardware +
    + iblrig.hardware_validation +
    + iblrig.hifi +
    + iblrig.misc +
    + iblrig.net +
    + iblrig.online_plots +
    + iblrig.path_helper +
    + iblrig.pydantic_definitions +
    + iblrig.raw_data_loaders +
    + iblrig.rig_component +
    + iblrig.scale +
    + iblrig.serial_singleton +
    + iblrig.session_creator +
    + iblrig.sound +
    + iblrig.tools +
    + iblrig.transfer_experiments +
    + iblrig.upgrade_iblrig +
    + iblrig.valve +
    + iblrig.version_management +
+ iblrig_tasks +
    + iblrig_tasks._iblrig_tasks_advancedChoiceWorld +
    + iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_biasedChoiceWorld +
    + iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_ephysChoiceWorld +
    + iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_habituationChoiceWorld +
    + iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_ImagingChoiceWorld +
    + iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld +
    + iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_passiveChoiceWorld +
    + iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_spontaneous +
    + iblrig_tasks._iblrig_tasks_spontaneous.task +
    + iblrig_tasks._iblrig_tasks_trainingChoiceWorld +
    + iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task +
    + iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld +
    + iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task +
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/reference.html b/reference.html new file mode 100644 index 000000000..452bcfdb8 --- /dev/null +++ b/reference.html @@ -0,0 +1,616 @@ + + + + + + + Reference — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Reference

+
+

Describing an Experiment

+
+

Experiment description file

+

All experiments are described by a file with the name +_ibl_experiment.description.yaml. This description file contains +details about the experiment such as, information about the devices used +to collect data, or the behavior tasks run during the experiment. The +content of this file is used to copy data from the acquisition computer +to the lab server and also determines the task pipeline that will be +used to extract the data on the lab servers. It’s accuracy in fully +describing the experiment is, therefore, very important!

+

Here is an example of a complete experiment description file for a +mesoscope experiment running two consecutive tasks, +biasedChoiceWorld followed by passiveChoiceWorld.

+
devices:
+  mesoscope:
+    mesoscope:
+      collection: raw_imaging_data*
+      sync_label: chrono
+  cameras:
+    belly:
+      collection: raw_video_data
+      sync_label: audio
+      width: 640
+      height: 512
+      fps: 30
+    left:
+      collection: raw_video_data
+      sync_label: audio
+    right:
+      collection: raw_video_data
+      sync_label: audio
+procedures:
+- Imaging
+projects:
+- ibl_mesoscope_active
+sync:
+  nidq:
+    acquisition_software: timeline
+    collection: raw_sync_data
+    extension: npy
+tasks:
+- _biasedChoiceWorld:
+    collection: raw_task_data_00
+    sync_label: bpod
+    extractors: [TrialRegisterRaw, ChoiceWorldTrialsTimeline, TrainingStatus]
+- passiveChoiceWorld:
+    collection: raw_task_data_01
+    sync_label: bpod
+    extractors: [PassiveRegisterRaw, PassiveTaskTimeline]
+version: 1.0.0
+
+
+
+
+

Breaking down the components of an experiment description file

+
+

Devices

+

The devices section in the experiment description file lists the set of +devices from which data was collection in the experiment. Supported +devices are Cameras, Microphone, Mesoscope, Neuropixel, Photometry and +Widefield.

+

The convention for this section is to have the device name followed by a +list of sub-devices, e.g.

+
devices:
+  cameras:
+    belly:
+      collection: raw_video_data
+      sync_label: audio
+      width: 640
+      height: 512
+      fps: 30
+    left:
+      collection: raw_video_data
+      sync_label: audio
+    right:
+      collection: raw_video_data
+      sync_label: audio
+
+
+

In the above example, cameras is the device and the sub-devices are +belly, left and right.

+

If there are no sub-devices, the sub-device is given the same name as +the device, e.g.

+
devices:
+  mesoscope:
+    mesoscope:
+      collection: raw_imaging_data*
+      sync_label: chrono
+
+
+

Each sub-device must have at least the following two keys - +collection - the folder containing the data - sync_label - the +name of the common ttl pulses in the channel map used to sync the +timestamps

+

Additional keys can also be specified for specific extractors, e.g. for +the belly camera the camera metadata passed into the camera extractor +task is defined in this file.

+
+
+

Procedures

+

The procedures section lists the set of procedures that apply to this +experiment. The list of possible procedures can be found +here.

+

As many procedure that apply to the experiment can be added e.g.

+
procedures:
+- Fiber photometry
+- Optical stimulation
+- Ephys recording with acute probe(s)
+
+
+
+
+

Projects

+

The projects section lists the set of projects that apply to this +experiment. The list of possible projects can be found +here.

+

As many projects that apply to the experiment can be added e.g.

+
projects:
+- ibl_neuropixel_brainwide_01
+- carandiniharris_midbrain_ibl
+
+
+
+
+

Sync

+

The sync section contains information about the device used to collect +the syncing data and the format of the data. Supported sync devices are +bpod, nidq, tdms, timeline. Only one sync device can be specified +per experiment description file and act as the main clock to which other +timeseries are synced.

+

An example of an experiment run with bpod as the main syncing device is,

+
sync:
+  bpod:
+    collection: raw_behavior_data
+    extension: bin
+
+
+

Another example for spikeglx electrophysiology recordings with +Neuropixel 1B probes use the nidq as main synchronisation.

+
sync:
+  nidq:
+    collection: raw_ephys_data
+    extension: bin
+    acquisition_software: spikeglx
+
+
+

Each sync device must have at least the following two keys - +collection - the folder containing the data - extension - the +file extension of the sync data

+

Optional keys include, for example acquisition_software, the +software used to acquire the sync pulses

+
+
+

Tasks

+

The tasks section contains a list of the behavioral protocols run during +the experiment. The name of the protocol must be given in the list e.g.

+
tasks:
+- _biasedChoiceWorld:
+    collection: raw_task_data_00
+    sync_label: bpod
+    extractors: [TrialRegisterRaw, ChoiceWorldTrialsTimeline, TrainingStatus]
+- passiveChoiceWorld:
+    collection: raw_task_data_01
+    sync_label: bpod
+    extractors: [PassiveRegisterRaw, PassiveTaskTimeline]
+
+
+

Each task must have at least the following two keys - collection - +the folder containing the data - sync_label - the name of the common +ttl pulses in the channel map used to sync the timestamps

+

The collection must be unique for each task. i.e. Data from two +tasks cannot be stored in the same folder.

+

If the Tasks used to extract the data are not the default tasks, the +extractors to use must be passed in as an additional key. The order of +the extractors defines their parent child relationship in the task +architecture.

+
+
+

Version

+

The version section gives version number of the experiment description +file

+
+
+
+
+

Quality check the task post-usage

+

Once a session is acquired, you can verify whether the trials data is extracted properly and that the sequence of events matches the expected logic of +the task.

+
+

Metrics definitions

+

All the metrics computed as part of the Task logic integrity QC (Task QC) are implemented in +ibllib. +When run at a behavior rig, they are computed using the Bpod data, without alignment to another DAQ’s clock.

+
+

Tip

+

The Task QC metrics definitions can be found in this documentation page. +See this page on how to write QC checks for a custom task protocol.

+
+

Some are essential, i.e. if they fail you should immediately take action and verify your rig, +and some are not as critical.

+

Essential taskQCs:

+
    +
  • check_audio_pre_trial

  • +
  • check_correct_trial_event_sequence

  • +
  • check_error_trial_event_sequence

  • +
  • check_n_trial_events

  • +
  • check_response_feedback_delays

  • +
  • check_reward_volume_set

  • +
  • check_reward_volumes

  • +
  • check_stimOn_goCue_delays

  • +
  • check_stimulus_move_before_goCue

  • +
  • check_wheel_move_before_feedback

  • +
  • check_wheel_freeze_during_quiescence

  • +
+

Non essential taskQCs:

+
    +
  • check_stimOff_itiIn_delays

  • +
  • check_positive_feedback_stimOff_delays

  • +
  • check_negative_feedback_stimOff_delays

  • +
  • check_wheel_move_during_closed_loop

  • +
  • check_response_stimFreeze_delays

  • +
  • check_detected_wheel_moves

  • +
  • check_trial_length

  • +
  • check_goCue_delays

  • +
  • check_errorCue_delays

  • +
  • check_stimOn_delays

  • +
  • check_stimOff_delays

  • +
  • check_iti_delays

  • +
  • check_stimFreeze_delays

  • +
  • check_wheel_integrity

  • +
+
+

Tip

+

The value returned by each metric is the proportion of trial that fail to pass the given test. +For example, if the value returned by check_errorCue_delays is 0.92, it means 8% of the trials failed this test.

+
+
+
+

Quantifying the task QC outcome at the session level

+

The criteria for whether a session passes the Task QC is:

+
    +
  • NOT_SET: default value (= not run yet)

  • +
  • FAIL: if at least one metric is < 95%

  • +
  • WARNING: if all metrics are >=95% , and at least one metric is <99 %

  • +
  • PASS: if all metrics are >= 99%

  • +
+

This aggregation is done on all metrics, regardless if they are essential or not.

+

The criteria is defined at +this code line

+
+
+

How to check the task QC outcome

+
+

Immediately after acquiring a session

+

At the behaviour PC, before the data have been copied, use the task_qc command with the session path:

+
task_qc C:\iblrigv8_data\Subjects\KS022\2019-12-10\001 --local
+
+
+

More information can be found here, or by running task_qc –help.

+
+
+

Once the session is registered on Alyx

+
    +
  1. Check on the Alyx webpage

    +

    From the session overview page on Alyx, +find your session click on See more session info. +The session QC is displayed in one of the right panels.

    +

    To get more information regarding which test pass or fail (contributing to this overall session QC), +you can click on the QC menu on the left. Bar-diagrams will appear, with essentials QCs on the +left, colored in green if passing.

    +
    +

    Tip

    +
    +

    You can hover over the bars with your mouse to easily know the name of the corresponding metric. +This is useful if the value of the metric is 0.

    +
    +
    +

    Warning

    +

    If an essential metric fails, run the Task QC Viewer to investigate why.

    +
    +
    +
  2. +
  3. Run the taskQC Viewer to investigate

    +
    +

    The application Task QC Viewer +enables to visualise the data streams of problematic trials.

    +
    +

    Tip

    +

    Unlike when run at the behaviour PC, after registration the QC is run on the final time-aligned data (if applicable).

    +
    +
    +

    Run the task QC metrics and viewer

    +

    Select the eid for your session to inspect, and run the following within the iblrig env:

    +
    +
    task_qc baecbddc-2b86-4eaf-a6f2-b30923225609
    +
    +
    +
    +
    +
    +
  4. +
+
+
+
+
+

Guide to develop a custom task

+
+

iblrigv8 design: inheritance

+

During the lifetime of the IBL project, we realized that multiple task variants combine with multiple hardware configurations and acquisition modalities, leading to a combinatorial explosion of possible tasks and related hardware.

+

This left us with the only option of developing a flexible task framework through hierarchical inheritance.

+
+
All tasks inherit from the iblrig.base_tasks.BaseSession class, which provides the following functionalities:
+
+
+

Additionally the iblrig.base_tasks module provides “hardware mixins”. Those are classes that provide hardware-specific functionalities, such as connecting to a Bpod or a rotary encoder. They are composed with the BaseSession class to create a task.

+
+

Warning

+

This sounds complicated ? It is ! +Forecasting all possible tasks and hardware add-ons and modification is fool’s errand, however we can go through specific examples of task implementations.

+
+
+
+

Guide to Creating Your Own Task

+

What Happens When Running an IBL Task?

+
    +
  1. The task constructor is invoked, executing the following steps:

    +
      +
    • Reading of settings: hardware and IBLRIG configurations.

    • +
    • Reading of task parameters.

    • +
    • Instantiation of hardware mixins.

    • +
    +
  2. +
  3. The task initiates the run() method. Prior to execution, this +method:

    +
      +
    • Launches the hardware modules.

    • +
    • Establishes a session folder.

    • +
    • Saves the parameters to disk.

    • +
    +
  4. +
  5. The experiment unfolds: the run() method triggers the _run() +method within the child class:

    +
      +
    • Typically, this involves a loop that generates a Bpod state +machine for each trial and runs it.

    • +
    +
  6. +
  7. Upon SIGINT or when the maximum trial count is reached, the +experiment concludes. The end of the run() method includes:

    +
      +
    • Saving the final parameter file.

    • +
    • Recording administered water and session performance on Alyx.

    • +
    • Halting the mixins.

    • +
    • Initiating local server transfer.

    • +
    +
  8. +
+
+
+

Examples

+
+

Where to write your task

+

After the installation of iblrig the project extraction repository is located at the root of the C: drive. +New tasks should be added to the C:\project_extraction\iblrig_custom_tasks folder to be made visible by the iblrig GUI. +We use a convention that the task name starts with the author identifier, followed by an underscore, followed by the task name, such as olivier_awesomeChoiceWorld.

+
+
+
olivier_awesomeChoiceWorld
    +
  • __init__.py

  • +
  • task.py

  • +
  • README.md

  • +
  • task_parameters.yaml

  • +
  • test_olivier_awesomeChoiceWorld.py

  • +
+
+
+
+
+
+

Example 1: variation on biased choice world

+

We will create a a choice world task that modifies a the quiescence period duration random draw policy. +In the task.py file, the first step is to create a new task class that inherits from the BiasedChoiceWorldSession class.

+

Then we want to make sure that the task bears a distinctive protocol name, _iblrig_tasks_imagingChoiceWorld. +We also create the command line entry point for the task that will be used by the iblrig GUI.

+

Also, in this case we can leverage the IBL infrastructure to perform extraction of the trials using existing extractors extractor_tasks = [‘TrialRegisterRaw’, ‘ChoiceWorldTrials’]

+
+
import iblrig.misc
+from iblrig.base_choice_world import BiasedChoiceWorldSession
+
+
+class Session(BiasedChoiceWorldSession):
+    protocol_name = "_iblrig_tasks_imagingChoiceWorld"
+
+    def __init__(self, *args, **kwargs):
+        self.extractor_tasks = ['TrialRegisterRaw', 'ChoiceWorldTrials']
+        super().__init__(*args, **kwargs)
+
+if __name__ == "__main__":  # pragma: no cover
+    kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()])
+    sess = Session(**kwargs)
+    sess.run()
+
+
+
+

In this case the parent class BiasedChoiceWorldSession has a method that draws the quiescence period. We are going to overload this method to add our own policy. This means the parent method will be fully replaced by our implementation. +The class now looks like this:

+
+
class Session(BiasedChoiceWorldSession):
+    protocol_name = "_iblrig_tasks_imagingChoiceWorld"
+
+    def draw_quiescent_period(self):
+        """
+        For this task we double the quiescence period texp draw and remove the absolute
+        offset of 200ms. The resulting is a truncated exp distribution between 400ms and 1 sec
+        """
+        return iblrig.misc.texp(factor=0.35 * 2, min_=0.2 * 2, max_=0.5 * 2)
+
+
+
+

Et voilà, in a few lines, we re-used the whole biased choice world implementation to add a custom parameter. This is the most trivial and easy example. +The full code is available here.

+
+
+

Example 2: re-writing a state-machine for a biased choice world task

+

In some instances changes in the task logic require to go deeper and re-write the sequence of task events. In bpod parlance, we are talking about rewritng the state-machine code.

+

Coming, for now here is an example of such a task.

+

#.. include:: reference_developer_guide.rst

+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/reference_description_file.html b/reference_description_file.html new file mode 100644 index 000000000..a55ece3e4 --- /dev/null +++ b/reference_description_file.html @@ -0,0 +1,321 @@ + + + + + + + Describing an Experiment — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Describing an Experiment

+
+

Experiment description file

+

All experiments are described by a file with the name +_ibl_experiment.description.yaml. This description file contains +details about the experiment such as, information about the devices used +to collect data, or the behavior tasks run during the experiment. The +content of this file is used to copy data from the acquisition computer +to the lab server and also determines the task pipeline that will be +used to extract the data on the lab servers. It’s accuracy in fully +describing the experiment is, therefore, very important!

+

Here is an example of a complete experiment description file for a +mesoscope experiment running two consecutive tasks, +biasedChoiceWorld followed by passiveChoiceWorld.

+
devices:
+  mesoscope:
+    mesoscope:
+      collection: raw_imaging_data*
+      sync_label: chrono
+  cameras:
+    belly:
+      collection: raw_video_data
+      sync_label: audio
+      width: 640
+      height: 512
+      fps: 30
+    left:
+      collection: raw_video_data
+      sync_label: audio
+    right:
+      collection: raw_video_data
+      sync_label: audio
+procedures:
+- Imaging
+projects:
+- ibl_mesoscope_active
+sync:
+  nidq:
+    acquisition_software: timeline
+    collection: raw_sync_data
+    extension: npy
+tasks:
+- _biasedChoiceWorld:
+    collection: raw_task_data_00
+    sync_label: bpod
+    extractors: [TrialRegisterRaw, ChoiceWorldTrialsTimeline, TrainingStatus]
+- passiveChoiceWorld:
+    collection: raw_task_data_01
+    sync_label: bpod
+    extractors: [PassiveRegisterRaw, PassiveTaskTimeline]
+version: 1.0.0
+
+
+
+
+

Breaking down the components of an experiment description file

+
+

Devices

+

The devices section in the experiment description file lists the set of +devices from which data was collection in the experiment. Supported +devices are Cameras, Microphone, Mesoscope, Neuropixel, Photometry and +Widefield.

+

The convention for this section is to have the device name followed by a +list of sub-devices, e.g.

+
devices:
+  cameras:
+    belly:
+      collection: raw_video_data
+      sync_label: audio
+      width: 640
+      height: 512
+      fps: 30
+    left:
+      collection: raw_video_data
+      sync_label: audio
+    right:
+      collection: raw_video_data
+      sync_label: audio
+
+
+

In the above example, cameras is the device and the sub-devices are +belly, left and right.

+

If there are no sub-devices, the sub-device is given the same name as +the device, e.g.

+
devices:
+  mesoscope:
+    mesoscope:
+      collection: raw_imaging_data*
+      sync_label: chrono
+
+
+

Each sub-device must have at least the following two keys - +collection - the folder containing the data - sync_label - the +name of the common ttl pulses in the channel map used to sync the +timestamps

+

Additional keys can also be specified for specific extractors, e.g. for +the belly camera the camera metadata passed into the camera extractor +task is defined in this file.

+
+
+

Procedures

+

The procedures section lists the set of procedures that apply to this +experiment. The list of possible procedures can be found +here.

+

As many procedure that apply to the experiment can be added e.g.

+
procedures:
+- Fiber photometry
+- Optical stimulation
+- Ephys recording with acute probe(s)
+
+
+
+
+

Projects

+

The projects section lists the set of projects that apply to this +experiment. The list of possible projects can be found +here.

+

As many projects that apply to the experiment can be added e.g.

+
projects:
+- ibl_neuropixel_brainwide_01
+- carandiniharris_midbrain_ibl
+
+
+
+
+

Sync

+

The sync section contains information about the device used to collect +the syncing data and the format of the data. Supported sync devices are +bpod, nidq, tdms, timeline. Only one sync device can be specified +per experiment description file and act as the main clock to which other +timeseries are synced.

+

An example of an experiment run with bpod as the main syncing device is,

+
sync:
+  bpod:
+    collection: raw_behavior_data
+    extension: bin
+
+
+

Another example for spikeglx electrophysiology recordings with +Neuropixel 1B probes use the nidq as main synchronisation.

+
sync:
+  nidq:
+    collection: raw_ephys_data
+    extension: bin
+    acquisition_software: spikeglx
+
+
+

Each sync device must have at least the following two keys - +collection - the folder containing the data - extension - the +file extension of the sync data

+

Optional keys include, for example acquisition_software, the +software used to acquire the sync pulses

+
+
+

Tasks

+

The tasks section contains a list of the behavioral protocols run during +the experiment. The name of the protocol must be given in the list e.g.

+
tasks:
+- _biasedChoiceWorld:
+    collection: raw_task_data_00
+    sync_label: bpod
+    extractors: [TrialRegisterRaw, ChoiceWorldTrialsTimeline, TrainingStatus]
+- passiveChoiceWorld:
+    collection: raw_task_data_01
+    sync_label: bpod
+    extractors: [PassiveRegisterRaw, PassiveTaskTimeline]
+
+
+

Each task must have at least the following two keys - collection - +the folder containing the data - sync_label - the name of the common +ttl pulses in the channel map used to sync the timestamps

+

The collection must be unique for each task. i.e. Data from two +tasks cannot be stored in the same folder.

+

If the Tasks used to extract the data are not the default tasks, the +extractors to use must be passed in as an additional key. The order of +the extractors defines their parent child relationship in the task +architecture.

+
+
+

Version

+

The version section gives version number of the experiment description +file

+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/reference_developer_guide.html b/reference_developer_guide.html new file mode 100644 index 000000000..4102cb969 --- /dev/null +++ b/reference_developer_guide.html @@ -0,0 +1,271 @@ + + + + + + + Developer Guide — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Developer Guide

+
+

Versioning Scheme

+

IBLRIG v8 uses Semantic Versioning. +Its version string (currently “8.24.1”) is a combination of three fields, separated by dots:

+

+MAJOR . MINOR . PATCH

    +
  • The MAJOR field is only incremented for breaking changes, i.e., changes that are not backward compatible with previous changes. +Releases of IBLRIG v8, for instance, are generally incompatible with IBLRIG v7.

  • +
  • The MINOR field will be incremented upon adding new, backwards compatible features.

  • +
  • The PATCH field will be incremented with each new, backwards compatible bugfix release that does not implement a new feature.

  • +
+

On the developer side, these 3 fields are manually controlled by, both

+
+
    +
  1. adjusting the variable __version__ in iblrig/__init__.py, and

  2. +
  3. adding the corresponding version string to a commit as a git tag, +for instance:

    +
    git tag 8.8.4
    +git push origin --tags
    +
    +
    +
  4. +
+
+

The version string displayed by IBLRIG may include additional fields, such as in “8.24.1.post3+dirty”. +Here,

+
    +
  • post3 indicates the third unversioned commit after the latest versioned release, and

  • +
  • dirty indicates the presence of uncommited changes in your local repository of IBLRIG.

  • +
+

Both of these fields are automatically inferred (by means of git describe) and do not require manual interaction from the +developer.

+
+
+

Package Management and Development Workflows with PDM

+

We use PDM to manage dependencies of IBLRIG. +PDM can also be used to run various commands with relevance to the development process without having to activate a virtual +environment first. +Please refer to PDM’s documentation for help with installing PDM.

+
+

Installing Developer Dependencies

+

To install additional dependencies needed for working on IBLRIG’s code-base, run:

+
pdm sync -d
+
+
+
+
+

Running Unit Tests

+

To run unit tests locally, run:

+
pdm run pytest
+
+
+

This will also generate a HTML based coverage report which can be found in the htmlcov directory.

+
+
+

Linting & Formatting

+

We use Ruff for linting and formatting our code-base in close accordance with the Black code +style.

+

To lint your code, run:

+
pdm run ruff check
+
+
+

Appending the flag --fix to the above command will automatically fix issues that are deemed safe to handle.

+

To reformat your code according to the Black code style run:

+
pdm run ruff format
+
+
+

Appending the flag --check to the above command will check your code for formatting issues without applying any changes. +Refer to Ruff Formater’s documentation for further details.

+
+
+
+

pre-commit

+

IBLRIG v8 supports pre-commit hooks. +Install pre-commit according to the official guide to enable automated code-checks on commits.

+
+
+

Release Checklist

+
    +
  1. update CHANGELOG.md including changes from the last tag

  2. +
  3. Pull request to iblrigv8dev

  4. +
  5. Check CI and eventually wet lab test

  6. +
  7. Pull request to iblrigv8

  8. +
  9. Merge PR

  10. +
  11. git tag the release in accordance to the version number below (after merge!)

  12. +
+
+
+

Building the documentation

+

To build the documentation, run:

+
pdm run sphinx-autobuild ./docs/source ./docs/build
+
+
+

You can also export the documentation to a PDF file:

+
pdm run make -C docs/ simplepdf
+
+
+

Find the exported PDF file in docs/build/simplepdf.

+
+

Contribute to the documentation

+

To write the documentation:

+
    +
  • Write the documentation in the iblrig/docs/source folder

  • +
  • If you are writing in a new file, add it to the index.rst so it appears in the table of content

  • +
  • Push all your changes to the iblrigv8dev branch; if this branch does not exist, create it first

  • +
+

To release the documentation onto the website:

+
    +
  • Wait for the next release, or

  • +
  • Manually trigger the GitHub action by clicking “Run Workflow” (select master) here

  • +
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/reference_task_qc.html b/reference_task_qc.html new file mode 100644 index 000000000..cbc346704 --- /dev/null +++ b/reference_task_qc.html @@ -0,0 +1,256 @@ + + + + + + + Quality check the task post-usage — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Quality check the task post-usage

+

Once a session is acquired, you can verify whether the trials data is extracted properly and that the sequence of events matches the expected logic of +the task.

+
+

Metrics definitions

+

All the metrics computed as part of the Task logic integrity QC (Task QC) are implemented in +ibllib. +When run at a behavior rig, they are computed using the Bpod data, without alignment to another DAQ’s clock.

+
+

Tip

+

The Task QC metrics definitions can be found in this documentation page. +See this page on how to write QC checks for a custom task protocol.

+
+

Some are essential, i.e. if they fail you should immediately take action and verify your rig, +and some are not as critical.

+

Essential taskQCs:

+
    +
  • check_audio_pre_trial

  • +
  • check_correct_trial_event_sequence

  • +
  • check_error_trial_event_sequence

  • +
  • check_n_trial_events

  • +
  • check_response_feedback_delays

  • +
  • check_reward_volume_set

  • +
  • check_reward_volumes

  • +
  • check_stimOn_goCue_delays

  • +
  • check_stimulus_move_before_goCue

  • +
  • check_wheel_move_before_feedback

  • +
  • check_wheel_freeze_during_quiescence

  • +
+

Non essential taskQCs:

+
    +
  • check_stimOff_itiIn_delays

  • +
  • check_positive_feedback_stimOff_delays

  • +
  • check_negative_feedback_stimOff_delays

  • +
  • check_wheel_move_during_closed_loop

  • +
  • check_response_stimFreeze_delays

  • +
  • check_detected_wheel_moves

  • +
  • check_trial_length

  • +
  • check_goCue_delays

  • +
  • check_errorCue_delays

  • +
  • check_stimOn_delays

  • +
  • check_stimOff_delays

  • +
  • check_iti_delays

  • +
  • check_stimFreeze_delays

  • +
  • check_wheel_integrity

  • +
+
+

Tip

+

The value returned by each metric is the proportion of trial that fail to pass the given test. +For example, if the value returned by check_errorCue_delays is 0.92, it means 8% of the trials failed this test.

+
+
+
+

Quantifying the task QC outcome at the session level

+

The criteria for whether a session passes the Task QC is:

+
    +
  • NOT_SET: default value (= not run yet)

  • +
  • FAIL: if at least one metric is < 95%

  • +
  • WARNING: if all metrics are >=95% , and at least one metric is <99 %

  • +
  • PASS: if all metrics are >= 99%

  • +
+

This aggregation is done on all metrics, regardless if they are essential or not.

+

The criteria is defined at +this code line

+
+
+

How to check the task QC outcome

+
+

Immediately after acquiring a session

+

At the behaviour PC, before the data have been copied, use the task_qc command with the session path:

+
task_qc C:\iblrigv8_data\Subjects\KS022\2019-12-10\001 --local
+
+
+

More information can be found here, or by running task_qc –help.

+
+
+

Once the session is registered on Alyx

+
    +
  1. Check on the Alyx webpage

    +

    From the session overview page on Alyx, +find your session click on See more session info. +The session QC is displayed in one of the right panels.

    +

    To get more information regarding which test pass or fail (contributing to this overall session QC), +you can click on the QC menu on the left. Bar-diagrams will appear, with essentials QCs on the +left, colored in green if passing.

    +
    +

    Tip

    +
    +

    You can hover over the bars with your mouse to easily know the name of the corresponding metric. +This is useful if the value of the metric is 0.

    +
    +
    +

    Warning

    +

    If an essential metric fails, run the Task QC Viewer to investigate why.

    +
    +
    +
  2. +
  3. Run the taskQC Viewer to investigate

    +
    +

    The application Task QC Viewer +enables to visualise the data streams of problematic trials.

    +
    +

    Tip

    +

    Unlike when run at the behaviour PC, after registration the QC is run on the final time-aligned data (if applicable).

    +
    +
    +

    Run the task QC metrics and viewer

    +

    Select the eid for your session to inspect, and run the following within the iblrig env:

    +
    +
    task_qc baecbddc-2b86-4eaf-a6f2-b30923225609
    +
    +
    +
    +
    +
    +
  4. +
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/reference_write_your_own_task.html b/reference_write_your_own_task.html new file mode 100644 index 000000000..4c76deef9 --- /dev/null +++ b/reference_write_your_own_task.html @@ -0,0 +1,265 @@ + + + + + + + Guide to develop a custom task — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Guide to develop a custom task

+
+

iblrigv8 design: inheritance

+

During the lifetime of the IBL project, we realized that multiple task variants combine with multiple hardware configurations and acquisition modalities, leading to a combinatorial explosion of possible tasks and related hardware.

+

This left us with the only option of developing a flexible task framework through hierarchical inheritance.

+
+
All tasks inherit from the iblrig.base_tasks.BaseSession class, which provides the following functionalities:
+
+
+

Additionally the iblrig.base_tasks module provides “hardware mixins”. Those are classes that provide hardware-specific functionalities, such as connecting to a Bpod or a rotary encoder. They are composed with the BaseSession class to create a task.

+
+

Warning

+

This sounds complicated ? It is ! +Forecasting all possible tasks and hardware add-ons and modification is fool’s errand, however we can go through specific examples of task implementations.

+
+
+
+

Guide to Creating Your Own Task

+

What Happens When Running an IBL Task?

+
    +
  1. The task constructor is invoked, executing the following steps:

    +
      +
    • Reading of settings: hardware and IBLRIG configurations.

    • +
    • Reading of task parameters.

    • +
    • Instantiation of hardware mixins.

    • +
    +
  2. +
  3. The task initiates the run() method. Prior to execution, this +method:

    +
      +
    • Launches the hardware modules.

    • +
    • Establishes a session folder.

    • +
    • Saves the parameters to disk.

    • +
    +
  4. +
  5. The experiment unfolds: the run() method triggers the _run() +method within the child class:

    +
      +
    • Typically, this involves a loop that generates a Bpod state +machine for each trial and runs it.

    • +
    +
  6. +
  7. Upon SIGINT or when the maximum trial count is reached, the +experiment concludes. The end of the run() method includes:

    +
      +
    • Saving the final parameter file.

    • +
    • Recording administered water and session performance on Alyx.

    • +
    • Halting the mixins.

    • +
    • Initiating local server transfer.

    • +
    +
  8. +
+
+
+

Examples

+
+

Where to write your task

+

After the installation of iblrig the project extraction repository is located at the root of the C: drive. +New tasks should be added to the C:\project_extraction\iblrig_custom_tasks folder to be made visible by the iblrig GUI. +We use a convention that the task name starts with the author identifier, followed by an underscore, followed by the task name, such as olivier_awesomeChoiceWorld.

+
+
+
olivier_awesomeChoiceWorld
    +
  • __init__.py

  • +
  • task.py

  • +
  • README.md

  • +
  • task_parameters.yaml

  • +
  • test_olivier_awesomeChoiceWorld.py

  • +
+
+
+
+
+
+

Example 1: variation on biased choice world

+

We will create a a choice world task that modifies a the quiescence period duration random draw policy. +In the task.py file, the first step is to create a new task class that inherits from the BiasedChoiceWorldSession class.

+

Then we want to make sure that the task bears a distinctive protocol name, _iblrig_tasks_imagingChoiceWorld. +We also create the command line entry point for the task that will be used by the iblrig GUI.

+

Also, in this case we can leverage the IBL infrastructure to perform extraction of the trials using existing extractors extractor_tasks = [‘TrialRegisterRaw’, ‘ChoiceWorldTrials’]

+
+
import iblrig.misc
+from iblrig.base_choice_world import BiasedChoiceWorldSession
+
+
+class Session(BiasedChoiceWorldSession):
+    protocol_name = "_iblrig_tasks_imagingChoiceWorld"
+
+    def __init__(self, *args, **kwargs):
+        self.extractor_tasks = ['TrialRegisterRaw', 'ChoiceWorldTrials']
+        super().__init__(*args, **kwargs)
+
+if __name__ == "__main__":  # pragma: no cover
+    kwargs = iblrig.misc.get_task_arguments(parents=[Session.extra_parser()])
+    sess = Session(**kwargs)
+    sess.run()
+
+
+
+

In this case the parent class BiasedChoiceWorldSession has a method that draws the quiescence period. We are going to overload this method to add our own policy. This means the parent method will be fully replaced by our implementation. +The class now looks like this:

+
+
class Session(BiasedChoiceWorldSession):
+    protocol_name = "_iblrig_tasks_imagingChoiceWorld"
+
+    def draw_quiescent_period(self):
+        """
+        For this task we double the quiescence period texp draw and remove the absolute
+        offset of 200ms. The resulting is a truncated exp distribution between 400ms and 1 sec
+        """
+        return iblrig.misc.texp(factor=0.35 * 2, min_=0.2 * 2, max_=0.5 * 2)
+
+
+
+

Et voilà, in a few lines, we re-used the whole biased choice world implementation to add a custom parameter. This is the most trivial and easy example. +The full code is available here.

+
+
+

Example 2: re-writing a state-machine for a biased choice world task

+

In some instances changes in the task logic require to go deeper and re-write the sequence of task events. In bpod parlance, we are talking about rewritng the state-machine code.

+

Coming, for now here is an example of such a task.

+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 000000000..2c2388559 --- /dev/null +++ b/search.html @@ -0,0 +1,155 @@ + + + + + + Search — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 000000000..50190c71a --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"8.10.0": [[288, "id60"]], "8.10.1": [[288, "id59"]], "8.10.2": [[288, "id58"]], "8.11.0": [[288, "id57"]], "8.11.1": [[288, "id56"]], "8.11.2": [[288, "id55"]], "8.11.3": [[288, "id54"]], "8.11.4": [[288, "id53"]], "8.11.5": [[288, "id52"]], "8.12.0": [[288, "id51"]], "8.12.1": [[288, "id50"]], "8.12.10": [[288, "id41"]], "8.12.11": [[288, "id40"]], "8.12.12": [[288, "id39"]], "8.12.13": [[288, "id38"]], "8.12.2": [[288, "id49"]], "8.12.3": [[288, "id48"]], "8.12.4": [[288, "id47"]], "8.12.5": [[288, "id46"]], "8.12.6": [[288, "id45"]], "8.12.7": [[288, "id44"]], "8.12.8": [[288, "id43"]], "8.12.9": [[288, "id42"]], "8.13.0": [[288, "id37"]], "8.13.1": [[288, "id36"]], "8.13.2": [[288, "id35"]], "8.13.3": [[288, "id34"]], "8.13.4": [[288, "id33"]], "8.13.5": [[288, "id32"]], "8.14.0": [[288, "id31"]], "8.14.1": [[288, "id30"]], "8.14.2": [[288, "id29"]], "8.15.0": [[288, "id28"]], "8.15.1": [[288, "id27"]], "8.15.2": [[288, "id26"]], "8.15.3": [[288, "id25"]], "8.15.4": [[288, "id24"]], "8.15.5": [[288, "id23"]], "8.15.6": [[288, "id22"]], "8.16.0": [[288, "id21"]], "8.16.1": [[288, "id20"]], "8.17.0": [[288, "id19"]], "8.18.0": [[288, "id18"]], "8.19.0": [[288, "id17"]], "8.19.1": [[288, "id16"]], "8.19.2": [[288, "id15"]], "8.19.3": [[288, "id14"]], "8.19.4": [[288, "id13"]], "8.19.5": [[288, "id12"]], "8.19.6": [[288, "id11"]], "8.20.0": [[288, "id10"]], "8.21.0": [[288, "id9"]], "8.21.1": [[288, "id8"]], "8.21.2": [[288, "id7"]], "8.22.0": [[288, "id6"]], "8.22.1": [[288, "id5"]], "8.23.0": [[288, "id4"]], "8.23.1": [[288, "id3"]], "8.24.0": [[288, "id2"]], "8.24.1": [[288, "id1"]], "8.9.0": [[288, "id65"]], "8.9.1": [[288, "id64"]], "8.9.2": [[288, "id63"]], "8.9.3": [[288, "id62"]], "8.9.4": [[288, "id61"]], "API Reference": [[0, null]], "Background": [[290, "background"], [292, null], [292, null], [292, null]], "Behind the Copy Scripts": [[298, "behind-the-copy-scripts"], [300, "behind-the-copy-scripts"]], "Breaking down the components of an experiment description file": [[293, "breaking-down-the-components-of-an-experiment-description-file"], [294, "breaking-down-the-components-of-an-experiment-description-file"]], "Bug Reports & Feature Requests": [[289, "bug-reports-feature-requests"]], "Building the documentation": [[295, "building-the-documentation"]], "Camera Issues": [[289, "camera-issues"]], "Chaining several tasks together": [[298, "chaining-several-tasks-together"], [299, "chaining-several-tasks-together"]], "Changelog": [[288, null]], "Clean-up local data": [[298, "clean-up-local-data"], [300, "clean-up-local-data"]], "Configuration Instructions": [[292, "configuration-instructions"]], "Contribute to the documentation": [[295, "contribute-to-the-documentation"]], "Copy command": [[298, "copy-command"], [298, "id5"], [301, "copy-command"], [302, "copy-command"]], "Copy commands": [[298, "copy-commands"], [300, null]], "Defining Default Position & Size of Bonsai Visualizers": [[289, "defining-default-position-size-of-bonsai-visualizers"]], "Describing an Experiment": [[293, "describing-an-experiment"], [294, null]], "Developer Guide": [[295, null]], "Devices": [[293, "devices"], [294, "devices"]], "Example 1: variation on biased choice world": [[293, "example-1-variation-on-biased-choice-world"], [297, "example-1-variation-on-biased-choice-world"]], "Example 2: re-writing a state-machine for a biased choice world task": [[293, "example-2-re-writing-a-state-machine-for-a-biased-choice-world-task"], [297, "example-2-re-writing-a-state-machine-for-a-biased-choice-world-task"]], "Example of workflow": [[298, "example-of-workflow"], [300, "example-of-workflow"]], "Examples": [[126, null], [159, null], [176, null], [207, null], [293, "examples"], [297, "examples"]], "Experiment description file": [[293, "experiment-description-file"], [294, "experiment-description-file"]], "First Aid": [[289, "first-aid"]], "Flushing the valve": [[298, "flushing-the-valve"], [299, "flushing-the-valve"]], "Frame2TTL": [[289, "frame2ttl"]], "Frequently Asked Questions": [[289, null]], "General": [[289, "general"]], "Guide to Creating Your Own Task": [[293, "guide-to-creating-your-own-task"], [297, "guide-to-creating-your-own-task"]], "Guide to develop a custom task": [[293, "guide-to-develop-a-custom-task"], [297, null]], "Hardware Guide": [[290, null]], "How to check the task QC outcome": [[293, "how-to-check-the-task-qc-outcome"], [296, "how-to-check-the-task-qc-outcome"]], "IBLRIG": [[291, null]], "Immediately after acquiring a session": [[293, "immediately-after-acquiring-a-session"], [296, "immediately-after-acquiring-a-session"]], "Installation guide": [[292, null]], "Installing Developer Dependencies": [[295, "installing-developer-dependencies"]], "Installing Python 3.10": [[292, "installing-python-3-10"]], "Installing Visual C++ Redistributable": [[292, "installing-visual-c-redistributable"]], "Installing drivers": [[298, "installing-drivers"], [302, "installing-drivers"]], "Installing iblrigv8": [[292, "installing-iblrigv8"]], "Interfacing with Alyx": [[298, "interfacing-with-alyx"], [299, "interfacing-with-alyx"]], "Links": [[291, "links"]], "Linting & Formatting": [[295, "linting-formatting"]], "Look at the raw data": [[298, "look-at-the-raw-data"], [301, "look-at-the-raw-data"]], "Make sure you can connect to Alyx !": [[292, "exercise-0"]], "Metrics definitions": [[293, "metrics-definitions"], [296, "metrics-definitions"]], "Neuropixel recording with iblrigv8": [[298, "neuropixel-recording-with-iblrigv8"], [301, null]], "Notes": [[7, null], [158, null], [207, null], [224, null], [247, null], [249, null], [251, null], [252, null]], "Once the session is registered on Alyx": [[293, "once-the-session-is-registered-on-alyx"], [296, "once-the-session-is-registered-on-alyx"]], "Package Management and Development Workflows with PDM": [[295, "package-management-and-development-workflows-with-pdm"]], "Preparing Windows PowerShell": [[292, "preparing-windows-powershell"]], "Prerequisites": [[292, "prerequisites-0"]], "Procedures": [[293, "procedures"], [294, "procedures"]], "Projects": [[293, "projects"], [294, "projects"]], "Quality check the task post-usage": [[293, "quality-check-the-task-post-usage"], [296, null]], "Quantifying the task QC outcome at the session level": [[293, "quantifying-the-task-qc-outcome-at-the-session-level"], [296, "quantifying-the-task-qc-outcome-at-the-session-level"]], "Reference": [[293, null]], "Release Checklist": [[295, "release-checklist"]], "Requirements": [[290, "requirements"]], "Rig Configuration Files": [[292, "rig-configuration-files"]], "Run the task QC metrics and viewer": [[293, "exercise-0"], [296, "exercise-0"]], "Running Unit Tests": [[295, "running-unit-tests"]], "Running a behaviour experiment": [[298, "running-a-behaviour-experiment"], [299, null]], "Running a single task": [[298, "running-a-single-task"], [299, "running-a-single-task"]], "Screen Issues": [[289, "screen-issues"]], "Setting up ONE": [[292, "setting-up-one"]], "Settings config": [[298, "settings-config"], [302, "settings-config"]], "Setup": [[298, "setup"], [298, "id3"], [301, "setup"], [302, "setup"]], "Sound Issues": [[289, "sound-issues"]], "Starting a Task": [[298, "starting-a-task"], [299, "starting-a-task"]], "Starting a task": [[298, "id1"], [298, "id4"], [301, "starting-a-task"], [302, "starting-a-task"]], "Supplementary Controls": [[298, "supplementary-controls"], [299, "supplementary-controls"]], "Switch to specific iblrig version": [[292, "switch-to-specific-iblrig-version"]], "Sync": [[293, "sync"], [294, "sync"]], "Tasks": [[293, "tasks"], [294, "tasks"]], "The Command Line Interface": [[298, "the-command-line-interface"], [299, "the-command-line-interface"]], "The Graphical User Interface": [[298, "the-graphical-user-interface"], [299, "the-graphical-user-interface"]], "Updating iblrigv8": [[292, "updating-iblrigv8"]], "Upgrade Procedure": [[290, "upgrade-procedure"]], "Upgrading Xonar AE to Bpod HiFi Module": [[290, "upgrading-xonar-ae-to-bpod-hifi-module"]], "Usage": [[298, "usage"], [298, "id2"], [298, "id6"], [300, "usage"], [301, "usage"], [302, "usage"]], "Using IBLRIG v8": [[298, null]], "Version": [[293, "version"], [294, "version"]], "Versioning Scheme": [[295, "versioning-scheme"]], "Video acquisition computer": [[298, "video-acquisition-computer"], [302, null]], "Where to write your task": [[293, null], [297, null]], "Workflow": [[298, "workflow"], [300, "workflow"]], "You can check that everything went fine by running the test suite:": [[292, "exercise-1"]], "iblrig": [[1, null]], "iblrig.base_choice_world": [[2, null]], "iblrig.base_choice_world.ActiveChoiceWorldSession": [[3, null]], "iblrig.base_choice_world.ActiveChoiceWorldTrialData": [[4, null]], "iblrig.base_choice_world.BiasedChoiceWorldSession": [[5, null]], "iblrig.base_choice_world.BiasedChoiceWorldTrialData": [[6, null]], "iblrig.base_choice_world.ChoiceWorldSession": [[7, null]], "iblrig.base_choice_world.ChoiceWorldTrialData": [[8, null]], "iblrig.base_choice_world.HabituationChoiceWorldSession": [[9, null]], "iblrig.base_choice_world.HabituationChoiceWorldTrialData": [[10, null]], "iblrig.base_choice_world.TrainingChoiceWorldSession": [[11, null]], "iblrig.base_choice_world.TrainingChoiceWorldTrialData": [[12, null]], "iblrig.base_tasks": [[13, null]], "iblrig.base_tasks.BaseSession": [[14, null]], "iblrig.base_tasks.BonsaiRecordingMixin": [[15, null]], "iblrig.base_tasks.BonsaiVisualStimulusMixin": [[16, null]], "iblrig.base_tasks.BpodMixin": [[17, null]], "iblrig.base_tasks.EmptySession": [[18, null]], "iblrig.base_tasks.Frame2TTLMixin": [[19, null]], "iblrig.base_tasks.HasBpod": [[20, null]], "iblrig.base_tasks.NetworkSession": [[21, null]], "iblrig.base_tasks.OSCClient": [[22, null]], "iblrig.base_tasks.RotaryEncoderMixin": [[23, null]], "iblrig.base_tasks.SoundMixin": [[24, null]], "iblrig.base_tasks.SpontaneousSession": [[25, null]], "iblrig.base_tasks.ValveMixin": [[26, null]], "iblrig.choiceworld": [[27, null]], "iblrig.choiceworld.compute_adaptive_reward_volume": [[28, null]], "iblrig.choiceworld.contrasts_set": [[29, null]], "iblrig.choiceworld.draw_training_contrast": [[30, null]], "iblrig.choiceworld.get_subject_training_info": [[31, null]], "iblrig.choiceworld.training_contrasts_probabilities": [[32, null]], "iblrig.choiceworld.training_phase_from_contrast_set": [[33, null]], "iblrig.commands": [[34, null]], "iblrig.commands.dir_path": [[35, null]], "iblrig.commands.flush": [[36, null]], "iblrig.commands.remove_local_sessions": [[37, null]], "iblrig.commands.transfer_data": [[38, null]], "iblrig.commands.transfer_data_cli": [[39, null]], "iblrig.commands.transfer_ephys_data_cli": [[40, null]], "iblrig.commands.transfer_video_data_cli": [[41, null]], "iblrig.commands.view_session": [[42, null]], "iblrig.constants": [[43, null]], "iblrig.ephys": [[44, null]], "iblrig.ephys.neuropixel24_micromanipulator_coordinates": [[45, null]], "iblrig.ephys.prepare_ephys_session": [[46, null]], "iblrig.ephys.prepare_ephys_session_cmd": [[47, null]], "iblrig.frame2ttl": [[48, null]], "iblrig.frame2ttl.Frame2TTL": [[49, null]], "iblrig.graphic": [[50, null]], "iblrig.graphic.numinput": [[51, null]], "iblrig.gui": [[52, null]], "iblrig.gui.frame2ttl": [[53, null]], "iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog": [[54, null]], "iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget": [[55, null]], "iblrig.gui.resources_rc": [[56, null]], "iblrig.gui.resources_rc.qCleanupResources": [[57, null]], "iblrig.gui.resources_rc.qInitResources": [[58, null]], "iblrig.gui.splash": [[59, null]], "iblrig.gui.splash.Splash": [[60, null]], "iblrig.gui.tab_about": [[61, null]], "iblrig.gui.tab_about.TabAbout": [[62, null]], "iblrig.gui.tab_data": [[63, null]], "iblrig.gui.tab_data.Column": [[64, null]], "iblrig.gui.tab_data.DataItemDelegate": [[65, null]], "iblrig.gui.tab_data.DataWorker": [[66, null]], "iblrig.gui.tab_data.TabData": [[67, null]], "iblrig.gui.tab_data.sizeof_fmt": [[68, null]], "iblrig.gui.tab_docs": [[69, null]], "iblrig.gui.tab_docs.CustomWebEnginePage": [[70, null]], "iblrig.gui.tab_docs.TabDocs": [[71, null]], "iblrig.gui.tab_log": [[72, null]], "iblrig.gui.tab_log.TabLog": [[73, null]], "iblrig.gui.tools": [[74, null]], "iblrig.gui.tools.AlyxObject": [[75, null]], "iblrig.gui.tools.DataFrameTableModel": [[76, null]], "iblrig.gui.tools.DiskSpaceIndicator": [[77, null]], "iblrig.gui.tools.LineEditAlyxUser": [[78, null]], "iblrig.gui.tools.RemoteDevicesItemModel": [[79, null]], "iblrig.gui.tools.RemoteDevicesListView": [[80, null]], "iblrig.gui.tools.StatefulButton": [[81, null]], "iblrig.gui.tools.Worker": [[82, null]], "iblrig.gui.tools.WorkerSignals": [[83, null]], "iblrig.gui.tools.convert_uis": [[84, null]], "iblrig.gui.ui_frame2ttl": [[85, null]], "iblrig.gui.ui_frame2ttl.Ui_frame2ttl": [[86, null]], "iblrig.gui.ui_login": [[87, null]], "iblrig.gui.ui_login.Ui_login": [[88, null]], "iblrig.gui.ui_splash": [[89, null]], "iblrig.gui.ui_splash.Ui_splash": [[90, null]], "iblrig.gui.ui_tab_about": [[91, null]], "iblrig.gui.ui_tab_about.Ui_TabAbout": [[92, null]], "iblrig.gui.ui_tab_data": [[93, null]], "iblrig.gui.ui_tab_data.Ui_TabData": [[94, null]], "iblrig.gui.ui_tab_docs": [[95, null]], "iblrig.gui.ui_tab_docs.Ui_TabDocs": [[96, null]], "iblrig.gui.ui_tab_log": [[97, null]], "iblrig.gui.ui_tab_log.Ui_TabLog": [[98, null]], "iblrig.gui.ui_tab_session": [[99, null]], "iblrig.gui.ui_tab_session.Ui_tabSession": [[100, null]], "iblrig.gui.ui_update": [[101, null]], "iblrig.gui.ui_update.Ui_update": [[102, null]], "iblrig.gui.ui_validation": [[103, null]], "iblrig.gui.ui_validation.Ui_validation": [[104, null]], "iblrig.gui.ui_valve": [[105, null]], "iblrig.gui.ui_valve.Ui_valve": [[106, null]], "iblrig.gui.ui_wizard": [[107, null]], "iblrig.gui.ui_wizard.Ui_wizard": [[108, null]], "iblrig.gui.validation": [[109, null]], "iblrig.gui.validation.StatusItem": [[110, null]], "iblrig.gui.validation.SystemValidationDialog": [[111, null]], "iblrig.gui.validation.ValidatorItem": [[112, null]], "iblrig.gui.valve": [[113, null]], "iblrig.gui.valve.CalibrationPlot": [[114, null]], "iblrig.gui.valve.ValveCalibrationDialog": [[115, null]], "iblrig.gui.wizard": [[116, null]], "iblrig.gui.wizard.LoginWindow": [[117, null]], "iblrig.gui.wizard.RigWizard": [[118, null]], "iblrig.gui.wizard.RigWizardModel": [[119, null]], "iblrig.gui.wizard.UpdateNotice": [[120, null]], "iblrig.gui.wizard.main": [[121, null]], "iblrig.hardware": [[122, null]], "iblrig.hardware.Bpod": [[123, null]], "iblrig.hardware.MyRotaryEncoder": [[124, null]], "iblrig.hardware.SOFTCODE": [[125, null]], "iblrig.hardware.restart_com_port": [[126, null]], "iblrig.hardware.sound_device_factory": [[127, null]], "iblrig.hardware_validation": [[128, null]], "iblrig.hardware_validation.Result": [[129, null]], "iblrig.hardware_validation.Status": [[130, null]], "iblrig.hardware_validation.ValidateHardwareError": [[131, null]], "iblrig.hardware_validation.Validator": [[132, null]], "iblrig.hardware_validation.ValidatorAlyx": [[133, null]], "iblrig.hardware_validation.ValidatorAmbientModule": [[134, null]], "iblrig.hardware_validation.ValidatorBpod": [[135, null]], "iblrig.hardware_validation.ValidatorCamera": [[136, null]], "iblrig.hardware_validation.ValidatorFrame2TTL": [[137, null]], "iblrig.hardware_validation.ValidatorGit": [[138, null]], "iblrig.hardware_validation.ValidatorMic": [[139, null]], "iblrig.hardware_validation.ValidatorRotaryEncoderModule": [[140, null]], "iblrig.hardware_validation.ValidatorSerial": [[141, null]], "iblrig.hardware_validation.ValidatorSound": [[142, null]], "iblrig.hardware_validation.ValidatorValve": [[143, null]], "iblrig.hardware_validation.get_all_validators": [[144, null]], "iblrig.hardware_validation.run_all_validators": [[145, null]], "iblrig.hardware_validation.run_all_validators_cli": [[146, null]], "iblrig.hifi": [[147, null]], "iblrig.hifi.HiFi": [[148, null]], "iblrig.hifi.HiFiException": [[149, null]], "iblrig.misc": [[150, null]], "iblrig.misc.draw_contrast": [[151, null]], "iblrig.misc.get_biased_probs": [[152, null]], "iblrig.misc.get_port_events": [[153, null]], "iblrig.misc.get_session_path": [[154, null]], "iblrig.misc.get_task_argument_parser": [[155, null]], "iblrig.misc.get_task_arguments": [[156, null]], "iblrig.misc.online_std": [[157, null]], "iblrig.misc.truncated_exponential": [[158, null]], "iblrig.net": [[159, null]], "iblrig.net.Auxiliaries": [[160, null]], "iblrig.net.ExpInfo": [[161, null]], "iblrig.net.check_uri_match": [[162, null]], "iblrig.net.get_remote_devices": [[163, null]], "iblrig.net.get_remote_devices_file": [[164, null]], "iblrig.net.get_server_communicator": [[165, null]], "iblrig.net.install_alyx_token": [[166, null]], "iblrig.net.read_stdin": [[167, null]], "iblrig.net.update_alyx_token": [[168, null]], "iblrig.online_plots": [[169, null]], "iblrig.online_plots.DataModel": [[170, null]], "iblrig.online_plots.OnlinePlots": [[171, null]], "iblrig.path_helper": [[172, null]], "iblrig.path_helper.create_bonsai_layout_from_template": [[173, null]], "iblrig.path_helper.get_commit_hash": [[174, null]], "iblrig.path_helper.get_local_and_remote_paths": [[175, null]], "iblrig.path_helper.iterate_collection": [[176, null]], "iblrig.path_helper.iterate_previous_sessions": [[177, null]], "iblrig.path_helper.load_pydantic_yaml": [[178, null]], "iblrig.path_helper.patch_settings": [[179, null]], "iblrig.path_helper.save_pydantic_yaml": [[180, null]], "iblrig.pydantic_definitions": [[181, null]], "iblrig.pydantic_definitions.BunchModel": [[182, null]], "iblrig.pydantic_definitions.ExistingFilePath": [[183, null]], "iblrig.pydantic_definitions.HardwareSettings": [[184, null]], "iblrig.pydantic_definitions.HardwareSettingsBpod": [[185, null]], "iblrig.pydantic_definitions.HardwareSettingsCamera": [[186, null]], "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow": [[187, null]], "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL": [[188, null]], "iblrig.pydantic_definitions.HardwareSettingsMicrophone": [[189, null]], "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder": [[190, null]], "iblrig.pydantic_definitions.HardwareSettingsScale": [[191, null]], "iblrig.pydantic_definitions.HardwareSettingsScreen": [[192, null]], "iblrig.pydantic_definitions.HardwareSettingsSound": [[193, null]], "iblrig.pydantic_definitions.HardwareSettingsValve": [[194, null]], "iblrig.pydantic_definitions.RigSettings": [[195, null]], "iblrig.pydantic_definitions.TrialDataModel": [[196, null]], "iblrig.raw_data_loaders": [[197, null]], "iblrig.raw_data_loaders.load_task_jsonable": [[198, null]], "iblrig.rig_component": [[199, null]], "iblrig.rig_component.RigComponent": [[200, null]], "iblrig.scale": [[201, null]], "iblrig.scale.Scale": [[202, null]], "iblrig.scale.ScaleData": [[203, null]], "iblrig.serial_singleton": [[204, null]], "iblrig.serial_singleton.SerialSingleton": [[205, null]], "iblrig.serial_singleton.SerialSingletonException": [[206, null]], "iblrig.serial_singleton.filter_ports": [[207, null]], "iblrig.serial_singleton.get_port_from_serial_number": [[208, null]], "iblrig.serial_singleton.get_serial_number_from_port": [[209, null]], "iblrig.session_creator": [[210, null]], "iblrig.session_creator.draw_block_len": [[211, null]], "iblrig.session_creator.draw_position": [[212, null]], "iblrig.session_creator.make_ephyscw_pc": [[213, null]], "iblrig.sound": [[214, null]], "iblrig.sound.configure_sound_card": [[215, null]], "iblrig.sound.format_sound": [[216, null]], "iblrig.sound.make_sound": [[217, null]], "iblrig.tools": [[218, null]], "iblrig.tools.ANSI": [[219, null]], "iblrig.tools.alyx_reachable": [[220, null]], "iblrig.tools.ask_user": [[221, null]], "iblrig.tools.call_bonsai": [[222, null]], "iblrig.tools.call_bonsai_async": [[223, null]], "iblrig.tools.get_anydesk_id": [[224, null]], "iblrig.tools.get_inheritors": [[225, null]], "iblrig.tools.get_lab_location_dict": [[226, null]], "iblrig.tools.internet_available": [[227, null]], "iblrig.tools.static_vars": [[228, null]], "iblrig.transfer_experiments": [[229, null]], "iblrig.transfer_experiments.BehaviorCopier": [[230, null]], "iblrig.transfer_experiments.CopyState": [[231, null]], "iblrig.transfer_experiments.EphysCopier": [[232, null]], "iblrig.transfer_experiments.SessionCopier": [[233, null]], "iblrig.transfer_experiments.VideoCopier": [[234, null]], "iblrig.transfer_experiments.copy_folders": [[235, null]], "iblrig.upgrade_iblrig": [[236, null]], "iblrig.upgrade_iblrig.call_subprocesses": [[237, null]], "iblrig.upgrade_iblrig.upgrade": [[238, null]], "iblrig.valve": [[239, null]], "iblrig.valve.Valve": [[240, null]], "iblrig.valve.ValveValues": [[241, null]], "iblrig.version_management": [[242, null]], "iblrig.version_management.call_git": [[243, null]], "iblrig.version_management.check_for_updates": [[244, null]], "iblrig.version_management.check_upgrade_prerequisites": [[245, null]], "iblrig.version_management.get_branch": [[246, null]], "iblrig.version_management.get_changelog": [[247, null]], "iblrig.version_management.get_commit_hash": [[248, null]], "iblrig.version_management.get_detailed_version_string": [[249, null]], "iblrig.version_management.get_local_version": [[250, null]], "iblrig.version_management.get_remote_tags": [[251, null]], "iblrig.version_management.get_remote_version": [[252, null]], "iblrig.version_management.is_dirty": [[253, null]], "iblrig_tasks": [[254, null]], "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld": [[255, null]], "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task": [[256, null]], "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session": [[257, null]], "iblrig_tasks._iblrig_tasks_advancedChoiceWorld": [[258, null]], "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task": [[259, null]], "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session": [[260, null]], "iblrig_tasks._iblrig_tasks_biasedChoiceWorld": [[261, null]], "iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task": [[262, null]], "iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session": [[263, null]], "iblrig_tasks._iblrig_tasks_ephysChoiceWorld": [[264, null]], "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task": [[265, null]], "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session": [[266, null]], "iblrig_tasks._iblrig_tasks_habituationChoiceWorld": [[267, null]], "iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task": [[268, null]], "iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session": [[269, null]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld": [[270, null]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task": [[271, null]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData": [[272, null]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session": [[273, null]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks": [[274, null]], "iblrig_tasks._iblrig_tasks_passiveChoiceWorld": [[275, null]], "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task": [[276, null]], "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session": [[277, null]], "iblrig_tasks._iblrig_tasks_spontaneous": [[278, null]], "iblrig_tasks._iblrig_tasks_spontaneous.task": [[279, null]], "iblrig_tasks._iblrig_tasks_spontaneous.task.Session": [[280, null]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld": [[281, null]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task": [[282, null]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session": [[283, null]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none": [[284, null]], "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld": [[285, null]], "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task": [[286, null]], "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session": [[287, null]], "iblrigv8 design: inheritance": [[293, "iblrigv8-design-inheritance"], [297, "iblrigv8-design-inheritance"]], "pre-commit": [[295, "pre-commit"]]}, "docnames": ["api", "api/iblrig", "api/iblrig.base_choice_world", "api/iblrig.base_choice_world.ActiveChoiceWorldSession", "api/iblrig.base_choice_world.ActiveChoiceWorldTrialData", "api/iblrig.base_choice_world.BiasedChoiceWorldSession", "api/iblrig.base_choice_world.BiasedChoiceWorldTrialData", "api/iblrig.base_choice_world.ChoiceWorldSession", "api/iblrig.base_choice_world.ChoiceWorldTrialData", "api/iblrig.base_choice_world.HabituationChoiceWorldSession", "api/iblrig.base_choice_world.HabituationChoiceWorldTrialData", "api/iblrig.base_choice_world.TrainingChoiceWorldSession", "api/iblrig.base_choice_world.TrainingChoiceWorldTrialData", "api/iblrig.base_tasks", "api/iblrig.base_tasks.BaseSession", "api/iblrig.base_tasks.BonsaiRecordingMixin", "api/iblrig.base_tasks.BonsaiVisualStimulusMixin", "api/iblrig.base_tasks.BpodMixin", "api/iblrig.base_tasks.EmptySession", "api/iblrig.base_tasks.Frame2TTLMixin", "api/iblrig.base_tasks.HasBpod", "api/iblrig.base_tasks.NetworkSession", "api/iblrig.base_tasks.OSCClient", "api/iblrig.base_tasks.RotaryEncoderMixin", "api/iblrig.base_tasks.SoundMixin", "api/iblrig.base_tasks.SpontaneousSession", "api/iblrig.base_tasks.ValveMixin", "api/iblrig.choiceworld", "api/iblrig.choiceworld.compute_adaptive_reward_volume", "api/iblrig.choiceworld.contrasts_set", "api/iblrig.choiceworld.draw_training_contrast", "api/iblrig.choiceworld.get_subject_training_info", "api/iblrig.choiceworld.training_contrasts_probabilities", "api/iblrig.choiceworld.training_phase_from_contrast_set", "api/iblrig.commands", "api/iblrig.commands.dir_path", "api/iblrig.commands.flush", "api/iblrig.commands.remove_local_sessions", "api/iblrig.commands.transfer_data", "api/iblrig.commands.transfer_data_cli", "api/iblrig.commands.transfer_ephys_data_cli", "api/iblrig.commands.transfer_video_data_cli", "api/iblrig.commands.view_session", "api/iblrig.constants", "api/iblrig.ephys", "api/iblrig.ephys.neuropixel24_micromanipulator_coordinates", "api/iblrig.ephys.prepare_ephys_session", "api/iblrig.ephys.prepare_ephys_session_cmd", "api/iblrig.frame2ttl", "api/iblrig.frame2ttl.Frame2TTL", "api/iblrig.graphic", "api/iblrig.graphic.numinput", "api/iblrig.gui", "api/iblrig.gui.frame2ttl", "api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog", "api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget", "api/iblrig.gui.resources_rc", "api/iblrig.gui.resources_rc.qCleanupResources", "api/iblrig.gui.resources_rc.qInitResources", "api/iblrig.gui.splash", "api/iblrig.gui.splash.Splash", "api/iblrig.gui.tab_about", "api/iblrig.gui.tab_about.TabAbout", "api/iblrig.gui.tab_data", "api/iblrig.gui.tab_data.Column", "api/iblrig.gui.tab_data.DataItemDelegate", "api/iblrig.gui.tab_data.DataWorker", "api/iblrig.gui.tab_data.TabData", "api/iblrig.gui.tab_data.sizeof_fmt", "api/iblrig.gui.tab_docs", "api/iblrig.gui.tab_docs.CustomWebEnginePage", "api/iblrig.gui.tab_docs.TabDocs", "api/iblrig.gui.tab_log", "api/iblrig.gui.tab_log.TabLog", "api/iblrig.gui.tools", "api/iblrig.gui.tools.AlyxObject", "api/iblrig.gui.tools.DataFrameTableModel", "api/iblrig.gui.tools.DiskSpaceIndicator", "api/iblrig.gui.tools.LineEditAlyxUser", "api/iblrig.gui.tools.RemoteDevicesItemModel", "api/iblrig.gui.tools.RemoteDevicesListView", "api/iblrig.gui.tools.StatefulButton", "api/iblrig.gui.tools.Worker", "api/iblrig.gui.tools.WorkerSignals", "api/iblrig.gui.tools.convert_uis", "api/iblrig.gui.ui_frame2ttl", "api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl", "api/iblrig.gui.ui_login", "api/iblrig.gui.ui_login.Ui_login", "api/iblrig.gui.ui_splash", "api/iblrig.gui.ui_splash.Ui_splash", "api/iblrig.gui.ui_tab_about", "api/iblrig.gui.ui_tab_about.Ui_TabAbout", "api/iblrig.gui.ui_tab_data", "api/iblrig.gui.ui_tab_data.Ui_TabData", "api/iblrig.gui.ui_tab_docs", "api/iblrig.gui.ui_tab_docs.Ui_TabDocs", "api/iblrig.gui.ui_tab_log", "api/iblrig.gui.ui_tab_log.Ui_TabLog", "api/iblrig.gui.ui_tab_session", "api/iblrig.gui.ui_tab_session.Ui_tabSession", "api/iblrig.gui.ui_update", "api/iblrig.gui.ui_update.Ui_update", "api/iblrig.gui.ui_validation", "api/iblrig.gui.ui_validation.Ui_validation", "api/iblrig.gui.ui_valve", "api/iblrig.gui.ui_valve.Ui_valve", "api/iblrig.gui.ui_wizard", "api/iblrig.gui.ui_wizard.Ui_wizard", "api/iblrig.gui.validation", "api/iblrig.gui.validation.StatusItem", "api/iblrig.gui.validation.SystemValidationDialog", "api/iblrig.gui.validation.ValidatorItem", "api/iblrig.gui.valve", "api/iblrig.gui.valve.CalibrationPlot", "api/iblrig.gui.valve.ValveCalibrationDialog", "api/iblrig.gui.wizard", "api/iblrig.gui.wizard.LoginWindow", "api/iblrig.gui.wizard.RigWizard", "api/iblrig.gui.wizard.RigWizardModel", "api/iblrig.gui.wizard.UpdateNotice", "api/iblrig.gui.wizard.main", "api/iblrig.hardware", "api/iblrig.hardware.Bpod", "api/iblrig.hardware.MyRotaryEncoder", "api/iblrig.hardware.SOFTCODE", "api/iblrig.hardware.restart_com_port", "api/iblrig.hardware.sound_device_factory", "api/iblrig.hardware_validation", "api/iblrig.hardware_validation.Result", "api/iblrig.hardware_validation.Status", "api/iblrig.hardware_validation.ValidateHardwareError", "api/iblrig.hardware_validation.Validator", "api/iblrig.hardware_validation.ValidatorAlyx", "api/iblrig.hardware_validation.ValidatorAmbientModule", "api/iblrig.hardware_validation.ValidatorBpod", "api/iblrig.hardware_validation.ValidatorCamera", "api/iblrig.hardware_validation.ValidatorFrame2TTL", "api/iblrig.hardware_validation.ValidatorGit", "api/iblrig.hardware_validation.ValidatorMic", "api/iblrig.hardware_validation.ValidatorRotaryEncoderModule", "api/iblrig.hardware_validation.ValidatorSerial", "api/iblrig.hardware_validation.ValidatorSound", "api/iblrig.hardware_validation.ValidatorValve", "api/iblrig.hardware_validation.get_all_validators", "api/iblrig.hardware_validation.run_all_validators", "api/iblrig.hardware_validation.run_all_validators_cli", "api/iblrig.hifi", "api/iblrig.hifi.HiFi", "api/iblrig.hifi.HiFiException", "api/iblrig.misc", "api/iblrig.misc.draw_contrast", "api/iblrig.misc.get_biased_probs", "api/iblrig.misc.get_port_events", "api/iblrig.misc.get_session_path", "api/iblrig.misc.get_task_argument_parser", "api/iblrig.misc.get_task_arguments", "api/iblrig.misc.online_std", "api/iblrig.misc.truncated_exponential", "api/iblrig.net", "api/iblrig.net.Auxiliaries", "api/iblrig.net.ExpInfo", "api/iblrig.net.check_uri_match", "api/iblrig.net.get_remote_devices", "api/iblrig.net.get_remote_devices_file", "api/iblrig.net.get_server_communicator", "api/iblrig.net.install_alyx_token", "api/iblrig.net.read_stdin", "api/iblrig.net.update_alyx_token", "api/iblrig.online_plots", "api/iblrig.online_plots.DataModel", "api/iblrig.online_plots.OnlinePlots", "api/iblrig.path_helper", "api/iblrig.path_helper.create_bonsai_layout_from_template", "api/iblrig.path_helper.get_commit_hash", "api/iblrig.path_helper.get_local_and_remote_paths", "api/iblrig.path_helper.iterate_collection", "api/iblrig.path_helper.iterate_previous_sessions", "api/iblrig.path_helper.load_pydantic_yaml", "api/iblrig.path_helper.patch_settings", "api/iblrig.path_helper.save_pydantic_yaml", "api/iblrig.pydantic_definitions", "api/iblrig.pydantic_definitions.BunchModel", "api/iblrig.pydantic_definitions.ExistingFilePath", "api/iblrig.pydantic_definitions.HardwareSettings", "api/iblrig.pydantic_definitions.HardwareSettingsBpod", "api/iblrig.pydantic_definitions.HardwareSettingsCamera", "api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow", "api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL", "api/iblrig.pydantic_definitions.HardwareSettingsMicrophone", "api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder", "api/iblrig.pydantic_definitions.HardwareSettingsScale", "api/iblrig.pydantic_definitions.HardwareSettingsScreen", "api/iblrig.pydantic_definitions.HardwareSettingsSound", "api/iblrig.pydantic_definitions.HardwareSettingsValve", "api/iblrig.pydantic_definitions.RigSettings", "api/iblrig.pydantic_definitions.TrialDataModel", "api/iblrig.raw_data_loaders", "api/iblrig.raw_data_loaders.load_task_jsonable", "api/iblrig.rig_component", "api/iblrig.rig_component.RigComponent", "api/iblrig.scale", "api/iblrig.scale.Scale", "api/iblrig.scale.ScaleData", "api/iblrig.serial_singleton", "api/iblrig.serial_singleton.SerialSingleton", "api/iblrig.serial_singleton.SerialSingletonException", "api/iblrig.serial_singleton.filter_ports", "api/iblrig.serial_singleton.get_port_from_serial_number", "api/iblrig.serial_singleton.get_serial_number_from_port", "api/iblrig.session_creator", "api/iblrig.session_creator.draw_block_len", "api/iblrig.session_creator.draw_position", "api/iblrig.session_creator.make_ephyscw_pc", "api/iblrig.sound", "api/iblrig.sound.configure_sound_card", "api/iblrig.sound.format_sound", "api/iblrig.sound.make_sound", "api/iblrig.tools", "api/iblrig.tools.ANSI", "api/iblrig.tools.alyx_reachable", "api/iblrig.tools.ask_user", "api/iblrig.tools.call_bonsai", "api/iblrig.tools.call_bonsai_async", "api/iblrig.tools.get_anydesk_id", "api/iblrig.tools.get_inheritors", "api/iblrig.tools.get_lab_location_dict", "api/iblrig.tools.internet_available", "api/iblrig.tools.static_vars", "api/iblrig.transfer_experiments", "api/iblrig.transfer_experiments.BehaviorCopier", "api/iblrig.transfer_experiments.CopyState", "api/iblrig.transfer_experiments.EphysCopier", "api/iblrig.transfer_experiments.SessionCopier", "api/iblrig.transfer_experiments.VideoCopier", "api/iblrig.transfer_experiments.copy_folders", "api/iblrig.upgrade_iblrig", "api/iblrig.upgrade_iblrig.call_subprocesses", "api/iblrig.upgrade_iblrig.upgrade", "api/iblrig.valve", "api/iblrig.valve.Valve", "api/iblrig.valve.ValveValues", "api/iblrig.version_management", "api/iblrig.version_management.call_git", "api/iblrig.version_management.check_for_updates", "api/iblrig.version_management.check_upgrade_prerequisites", "api/iblrig.version_management.get_branch", "api/iblrig.version_management.get_changelog", "api/iblrig.version_management.get_commit_hash", "api/iblrig.version_management.get_detailed_version_string", "api/iblrig.version_management.get_local_version", "api/iblrig.version_management.get_remote_tags", "api/iblrig.version_management.get_remote_version", "api/iblrig.version_management.is_dirty", "api/iblrig_tasks", "api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld", "api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld", "api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld", "api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld", "api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld", "api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks", "api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld", "api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_spontaneous", "api/iblrig_tasks._iblrig_tasks_spontaneous.task", "api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none", "api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld", "api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task", "api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session", "changelog", "faq", "hardware", "index", "installation", "reference", "reference_description_file", "reference_developer_guide", "reference_task_qc", "reference_write_your_own_task", "usage", "usage_behavior", "usage_copy", "usage_neuropixel", "usage_video"], "envversion": {"sphinx": 62, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.viewcode": 1}, "filenames": ["api.rst", "api/iblrig.rst", "api/iblrig.base_choice_world.rst", "api/iblrig.base_choice_world.ActiveChoiceWorldSession.rst", "api/iblrig.base_choice_world.ActiveChoiceWorldTrialData.rst", "api/iblrig.base_choice_world.BiasedChoiceWorldSession.rst", "api/iblrig.base_choice_world.BiasedChoiceWorldTrialData.rst", "api/iblrig.base_choice_world.ChoiceWorldSession.rst", "api/iblrig.base_choice_world.ChoiceWorldTrialData.rst", "api/iblrig.base_choice_world.HabituationChoiceWorldSession.rst", "api/iblrig.base_choice_world.HabituationChoiceWorldTrialData.rst", "api/iblrig.base_choice_world.TrainingChoiceWorldSession.rst", "api/iblrig.base_choice_world.TrainingChoiceWorldTrialData.rst", "api/iblrig.base_tasks.rst", "api/iblrig.base_tasks.BaseSession.rst", "api/iblrig.base_tasks.BonsaiRecordingMixin.rst", "api/iblrig.base_tasks.BonsaiVisualStimulusMixin.rst", "api/iblrig.base_tasks.BpodMixin.rst", "api/iblrig.base_tasks.EmptySession.rst", "api/iblrig.base_tasks.Frame2TTLMixin.rst", "api/iblrig.base_tasks.HasBpod.rst", "api/iblrig.base_tasks.NetworkSession.rst", "api/iblrig.base_tasks.OSCClient.rst", "api/iblrig.base_tasks.RotaryEncoderMixin.rst", "api/iblrig.base_tasks.SoundMixin.rst", "api/iblrig.base_tasks.SpontaneousSession.rst", "api/iblrig.base_tasks.ValveMixin.rst", "api/iblrig.choiceworld.rst", "api/iblrig.choiceworld.compute_adaptive_reward_volume.rst", "api/iblrig.choiceworld.contrasts_set.rst", "api/iblrig.choiceworld.draw_training_contrast.rst", "api/iblrig.choiceworld.get_subject_training_info.rst", "api/iblrig.choiceworld.training_contrasts_probabilities.rst", "api/iblrig.choiceworld.training_phase_from_contrast_set.rst", "api/iblrig.commands.rst", "api/iblrig.commands.dir_path.rst", "api/iblrig.commands.flush.rst", "api/iblrig.commands.remove_local_sessions.rst", "api/iblrig.commands.transfer_data.rst", "api/iblrig.commands.transfer_data_cli.rst", "api/iblrig.commands.transfer_ephys_data_cli.rst", "api/iblrig.commands.transfer_video_data_cli.rst", "api/iblrig.commands.view_session.rst", "api/iblrig.constants.rst", "api/iblrig.ephys.rst", "api/iblrig.ephys.neuropixel24_micromanipulator_coordinates.rst", "api/iblrig.ephys.prepare_ephys_session.rst", "api/iblrig.ephys.prepare_ephys_session_cmd.rst", "api/iblrig.frame2ttl.rst", "api/iblrig.frame2ttl.Frame2TTL.rst", "api/iblrig.graphic.rst", "api/iblrig.graphic.numinput.rst", "api/iblrig.gui.rst", "api/iblrig.gui.frame2ttl.rst", "api/iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.rst", "api/iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.rst", "api/iblrig.gui.resources_rc.rst", "api/iblrig.gui.resources_rc.qCleanupResources.rst", "api/iblrig.gui.resources_rc.qInitResources.rst", "api/iblrig.gui.splash.rst", "api/iblrig.gui.splash.Splash.rst", "api/iblrig.gui.tab_about.rst", "api/iblrig.gui.tab_about.TabAbout.rst", "api/iblrig.gui.tab_data.rst", "api/iblrig.gui.tab_data.Column.rst", "api/iblrig.gui.tab_data.DataItemDelegate.rst", "api/iblrig.gui.tab_data.DataWorker.rst", "api/iblrig.gui.tab_data.TabData.rst", "api/iblrig.gui.tab_data.sizeof_fmt.rst", "api/iblrig.gui.tab_docs.rst", "api/iblrig.gui.tab_docs.CustomWebEnginePage.rst", "api/iblrig.gui.tab_docs.TabDocs.rst", "api/iblrig.gui.tab_log.rst", "api/iblrig.gui.tab_log.TabLog.rst", "api/iblrig.gui.tools.rst", "api/iblrig.gui.tools.AlyxObject.rst", "api/iblrig.gui.tools.DataFrameTableModel.rst", "api/iblrig.gui.tools.DiskSpaceIndicator.rst", "api/iblrig.gui.tools.LineEditAlyxUser.rst", "api/iblrig.gui.tools.RemoteDevicesItemModel.rst", "api/iblrig.gui.tools.RemoteDevicesListView.rst", "api/iblrig.gui.tools.StatefulButton.rst", "api/iblrig.gui.tools.Worker.rst", "api/iblrig.gui.tools.WorkerSignals.rst", "api/iblrig.gui.tools.convert_uis.rst", "api/iblrig.gui.ui_frame2ttl.rst", "api/iblrig.gui.ui_frame2ttl.Ui_frame2ttl.rst", "api/iblrig.gui.ui_login.rst", "api/iblrig.gui.ui_login.Ui_login.rst", "api/iblrig.gui.ui_splash.rst", "api/iblrig.gui.ui_splash.Ui_splash.rst", "api/iblrig.gui.ui_tab_about.rst", "api/iblrig.gui.ui_tab_about.Ui_TabAbout.rst", "api/iblrig.gui.ui_tab_data.rst", "api/iblrig.gui.ui_tab_data.Ui_TabData.rst", "api/iblrig.gui.ui_tab_docs.rst", "api/iblrig.gui.ui_tab_docs.Ui_TabDocs.rst", "api/iblrig.gui.ui_tab_log.rst", "api/iblrig.gui.ui_tab_log.Ui_TabLog.rst", "api/iblrig.gui.ui_tab_session.rst", "api/iblrig.gui.ui_tab_session.Ui_tabSession.rst", "api/iblrig.gui.ui_update.rst", "api/iblrig.gui.ui_update.Ui_update.rst", "api/iblrig.gui.ui_validation.rst", "api/iblrig.gui.ui_validation.Ui_validation.rst", "api/iblrig.gui.ui_valve.rst", "api/iblrig.gui.ui_valve.Ui_valve.rst", "api/iblrig.gui.ui_wizard.rst", "api/iblrig.gui.ui_wizard.Ui_wizard.rst", "api/iblrig.gui.validation.rst", "api/iblrig.gui.validation.StatusItem.rst", "api/iblrig.gui.validation.SystemValidationDialog.rst", "api/iblrig.gui.validation.ValidatorItem.rst", "api/iblrig.gui.valve.rst", "api/iblrig.gui.valve.CalibrationPlot.rst", "api/iblrig.gui.valve.ValveCalibrationDialog.rst", "api/iblrig.gui.wizard.rst", "api/iblrig.gui.wizard.LoginWindow.rst", "api/iblrig.gui.wizard.RigWizard.rst", "api/iblrig.gui.wizard.RigWizardModel.rst", "api/iblrig.gui.wizard.UpdateNotice.rst", "api/iblrig.gui.wizard.main.rst", "api/iblrig.hardware.rst", "api/iblrig.hardware.Bpod.rst", "api/iblrig.hardware.MyRotaryEncoder.rst", "api/iblrig.hardware.SOFTCODE.rst", "api/iblrig.hardware.restart_com_port.rst", "api/iblrig.hardware.sound_device_factory.rst", "api/iblrig.hardware_validation.rst", "api/iblrig.hardware_validation.Result.rst", "api/iblrig.hardware_validation.Status.rst", "api/iblrig.hardware_validation.ValidateHardwareError.rst", "api/iblrig.hardware_validation.Validator.rst", "api/iblrig.hardware_validation.ValidatorAlyx.rst", "api/iblrig.hardware_validation.ValidatorAmbientModule.rst", "api/iblrig.hardware_validation.ValidatorBpod.rst", "api/iblrig.hardware_validation.ValidatorCamera.rst", "api/iblrig.hardware_validation.ValidatorFrame2TTL.rst", "api/iblrig.hardware_validation.ValidatorGit.rst", "api/iblrig.hardware_validation.ValidatorMic.rst", "api/iblrig.hardware_validation.ValidatorRotaryEncoderModule.rst", "api/iblrig.hardware_validation.ValidatorSerial.rst", "api/iblrig.hardware_validation.ValidatorSound.rst", "api/iblrig.hardware_validation.ValidatorValve.rst", "api/iblrig.hardware_validation.get_all_validators.rst", "api/iblrig.hardware_validation.run_all_validators.rst", "api/iblrig.hardware_validation.run_all_validators_cli.rst", "api/iblrig.hifi.rst", "api/iblrig.hifi.HiFi.rst", "api/iblrig.hifi.HiFiException.rst", "api/iblrig.misc.rst", "api/iblrig.misc.draw_contrast.rst", "api/iblrig.misc.get_biased_probs.rst", "api/iblrig.misc.get_port_events.rst", "api/iblrig.misc.get_session_path.rst", "api/iblrig.misc.get_task_argument_parser.rst", "api/iblrig.misc.get_task_arguments.rst", "api/iblrig.misc.online_std.rst", "api/iblrig.misc.truncated_exponential.rst", "api/iblrig.net.rst", "api/iblrig.net.Auxiliaries.rst", "api/iblrig.net.ExpInfo.rst", "api/iblrig.net.check_uri_match.rst", "api/iblrig.net.get_remote_devices.rst", "api/iblrig.net.get_remote_devices_file.rst", "api/iblrig.net.get_server_communicator.rst", "api/iblrig.net.install_alyx_token.rst", "api/iblrig.net.read_stdin.rst", "api/iblrig.net.update_alyx_token.rst", "api/iblrig.online_plots.rst", "api/iblrig.online_plots.DataModel.rst", "api/iblrig.online_plots.OnlinePlots.rst", "api/iblrig.path_helper.rst", "api/iblrig.path_helper.create_bonsai_layout_from_template.rst", "api/iblrig.path_helper.get_commit_hash.rst", "api/iblrig.path_helper.get_local_and_remote_paths.rst", "api/iblrig.path_helper.iterate_collection.rst", "api/iblrig.path_helper.iterate_previous_sessions.rst", "api/iblrig.path_helper.load_pydantic_yaml.rst", "api/iblrig.path_helper.patch_settings.rst", "api/iblrig.path_helper.save_pydantic_yaml.rst", "api/iblrig.pydantic_definitions.rst", "api/iblrig.pydantic_definitions.BunchModel.rst", "api/iblrig.pydantic_definitions.ExistingFilePath.rst", "api/iblrig.pydantic_definitions.HardwareSettings.rst", "api/iblrig.pydantic_definitions.HardwareSettingsBpod.rst", "api/iblrig.pydantic_definitions.HardwareSettingsCamera.rst", "api/iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.rst", "api/iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.rst", "api/iblrig.pydantic_definitions.HardwareSettingsMicrophone.rst", "api/iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.rst", "api/iblrig.pydantic_definitions.HardwareSettingsScale.rst", "api/iblrig.pydantic_definitions.HardwareSettingsScreen.rst", "api/iblrig.pydantic_definitions.HardwareSettingsSound.rst", "api/iblrig.pydantic_definitions.HardwareSettingsValve.rst", "api/iblrig.pydantic_definitions.RigSettings.rst", "api/iblrig.pydantic_definitions.TrialDataModel.rst", "api/iblrig.raw_data_loaders.rst", "api/iblrig.raw_data_loaders.load_task_jsonable.rst", "api/iblrig.rig_component.rst", "api/iblrig.rig_component.RigComponent.rst", "api/iblrig.scale.rst", "api/iblrig.scale.Scale.rst", "api/iblrig.scale.ScaleData.rst", "api/iblrig.serial_singleton.rst", "api/iblrig.serial_singleton.SerialSingleton.rst", "api/iblrig.serial_singleton.SerialSingletonException.rst", "api/iblrig.serial_singleton.filter_ports.rst", "api/iblrig.serial_singleton.get_port_from_serial_number.rst", "api/iblrig.serial_singleton.get_serial_number_from_port.rst", "api/iblrig.session_creator.rst", "api/iblrig.session_creator.draw_block_len.rst", "api/iblrig.session_creator.draw_position.rst", "api/iblrig.session_creator.make_ephyscw_pc.rst", "api/iblrig.sound.rst", "api/iblrig.sound.configure_sound_card.rst", "api/iblrig.sound.format_sound.rst", "api/iblrig.sound.make_sound.rst", "api/iblrig.tools.rst", "api/iblrig.tools.ANSI.rst", "api/iblrig.tools.alyx_reachable.rst", "api/iblrig.tools.ask_user.rst", "api/iblrig.tools.call_bonsai.rst", "api/iblrig.tools.call_bonsai_async.rst", "api/iblrig.tools.get_anydesk_id.rst", "api/iblrig.tools.get_inheritors.rst", "api/iblrig.tools.get_lab_location_dict.rst", "api/iblrig.tools.internet_available.rst", "api/iblrig.tools.static_vars.rst", "api/iblrig.transfer_experiments.rst", "api/iblrig.transfer_experiments.BehaviorCopier.rst", "api/iblrig.transfer_experiments.CopyState.rst", "api/iblrig.transfer_experiments.EphysCopier.rst", "api/iblrig.transfer_experiments.SessionCopier.rst", "api/iblrig.transfer_experiments.VideoCopier.rst", "api/iblrig.transfer_experiments.copy_folders.rst", "api/iblrig.upgrade_iblrig.rst", "api/iblrig.upgrade_iblrig.call_subprocesses.rst", "api/iblrig.upgrade_iblrig.upgrade.rst", "api/iblrig.valve.rst", "api/iblrig.valve.Valve.rst", "api/iblrig.valve.ValveValues.rst", "api/iblrig.version_management.rst", "api/iblrig.version_management.call_git.rst", "api/iblrig.version_management.check_for_updates.rst", "api/iblrig.version_management.check_upgrade_prerequisites.rst", "api/iblrig.version_management.get_branch.rst", "api/iblrig.version_management.get_changelog.rst", "api/iblrig.version_management.get_commit_hash.rst", "api/iblrig.version_management.get_detailed_version_string.rst", "api/iblrig.version_management.get_local_version.rst", "api/iblrig.version_management.get_remote_tags.rst", "api/iblrig.version_management.get_remote_version.rst", "api/iblrig.version_management.is_dirty.rst", "api/iblrig_tasks.rst", "api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.rst", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.rst", "api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_spontaneous.rst", "api/iblrig_tasks._iblrig_tasks_spontaneous.task.rst", "api/iblrig_tasks._iblrig_tasks_spontaneous.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.rst", "api/iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none.rst", "api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.rst", "api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.rst", "api/iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.rst", "changelog.rst", "faq.rst", "hardware.rst", "index.rst", "installation.rst", "reference.rst", "reference_description_file.rst", "reference_developer_guide.rst", "reference_task_qc.rst", "reference_write_your_own_task.rst", "usage.rst", "usage_behavior.rst", "usage_copy.rst", "usage_neuropixel.rst", "usage_video.rst"], "indexentries": {"__init__() (iblrig.base_choice_world.activechoiceworldsession method)": [[3, "iblrig.base_choice_world.ActiveChoiceWorldSession.__init__", false]], "__init__() (iblrig.base_choice_world.biasedchoiceworldsession method)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.__init__", false]], "__init__() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.__init__", false]], "__init__() (iblrig.base_choice_world.trainingchoiceworldsession method)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.__init__", false]], "__init__() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.__init__", false]], "__init__() (iblrig.base_tasks.hasbpod method)": [[20, "iblrig.base_tasks.HasBpod.__init__", false]], "__init__() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.__init__", false]], "__init__() (iblrig.base_tasks.oscclient method)": [[22, "iblrig.base_tasks.OSCClient.__init__", false]], "__init__() (iblrig.base_tasks.spontaneoussession method)": [[25, "iblrig.base_tasks.SpontaneousSession.__init__", false]], "__init__() (iblrig.frame2ttl.frame2ttl method)": [[49, "iblrig.frame2ttl.Frame2TTL.__init__", false]], "__init__() (iblrig.gui.frame2ttl.frame2ttlcalibrationdialog method)": [[54, "iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog.__init__", false]], "__init__() (iblrig.gui.frame2ttl.frame2ttlcalibrationtarget method)": [[55, "iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.__init__", false]], "__init__() (iblrig.gui.splash.splash method)": [[60, "iblrig.gui.splash.Splash.__init__", false]], "__init__() (iblrig.gui.tab_about.tababout method)": [[62, "iblrig.gui.tab_about.TabAbout.__init__", false]], "__init__() (iblrig.gui.tab_data.dataworker method)": [[66, "iblrig.gui.tab_data.DataWorker.__init__", false]], "__init__() (iblrig.gui.tab_data.tabdata method)": [[67, "iblrig.gui.tab_data.TabData.__init__", false]], "__init__() (iblrig.gui.tab_docs.tabdocs method)": [[71, "iblrig.gui.tab_docs.TabDocs.__init__", false]], "__init__() (iblrig.gui.tab_log.tablog method)": [[73, "iblrig.gui.tab_log.TabLog.__init__", false]], "__init__() (iblrig.gui.tools.alyxobject method)": [[75, "iblrig.gui.tools.AlyxObject.__init__", false]], "__init__() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.__init__", false]], "__init__() (iblrig.gui.tools.diskspaceindicator method)": [[77, "iblrig.gui.tools.DiskSpaceIndicator.__init__", false]], "__init__() (iblrig.gui.tools.lineeditalyxuser method)": [[78, "iblrig.gui.tools.LineEditAlyxUser.__init__", false]], "__init__() (iblrig.gui.tools.remotedevicesitemmodel method)": [[79, "iblrig.gui.tools.RemoteDevicesItemModel.__init__", false]], "__init__() (iblrig.gui.tools.remotedeviceslistview method)": [[80, "iblrig.gui.tools.RemoteDevicesListView.__init__", false]], "__init__() (iblrig.gui.tools.statefulbutton method)": [[81, "iblrig.gui.tools.StatefulButton.__init__", false]], "__init__() (iblrig.gui.tools.worker method)": [[82, "iblrig.gui.tools.Worker.__init__", false]], "__init__() (iblrig.gui.validation.statusitem method)": [[110, "iblrig.gui.validation.StatusItem.__init__", false]], "__init__() (iblrig.gui.validation.systemvalidationdialog method)": [[111, "iblrig.gui.validation.SystemValidationDialog.__init__", false]], "__init__() (iblrig.gui.validation.validatoritem method)": [[112, "iblrig.gui.validation.ValidatorItem.__init__", false]], "__init__() (iblrig.gui.valve.calibrationplot method)": [[114, "iblrig.gui.valve.CalibrationPlot.__init__", false]], "__init__() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.__init__", false]], "__init__() (iblrig.gui.wizard.loginwindow method)": [[117, "iblrig.gui.wizard.LoginWindow.__init__", false]], "__init__() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.__init__", false]], "__init__() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.__init__", false]], "__init__() (iblrig.gui.wizard.updatenotice method)": [[120, "iblrig.gui.wizard.UpdateNotice.__init__", false]], "__init__() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.__init__", false]], "__init__() (iblrig.hardware.myrotaryencoder method)": [[124, "iblrig.hardware.MyRotaryEncoder.__init__", false]], "__init__() (iblrig.hardware_validation.result method)": [[129, "iblrig.hardware_validation.Result.__init__", false]], "__init__() (iblrig.hardware_validation.validator method)": [[132, "iblrig.hardware_validation.Validator.__init__", false]], "__init__() (iblrig.hardware_validation.validatorserial method)": [[141, "iblrig.hardware_validation.ValidatorSerial.__init__", false]], "__init__() (iblrig.hardware_validation.validatorsound method)": [[142, "iblrig.hardware_validation.ValidatorSound.__init__", false]], "__init__() (iblrig.hifi.hifi method)": [[148, "iblrig.hifi.HiFi.__init__", false]], "__init__() (iblrig.hifi.hifiexception method)": [[149, "iblrig.hifi.HiFiException.__init__", false]], "__init__() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.__init__", false]], "__init__() (iblrig.net.expinfo method)": [[161, "iblrig.net.ExpInfo.__init__", false]], "__init__() (iblrig.online_plots.datamodel method)": [[170, "iblrig.online_plots.DataModel.__init__", false]], "__init__() (iblrig.online_plots.onlineplots method)": [[171, "iblrig.online_plots.OnlinePlots.__init__", false]], "__init__() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.__init__", false]], "__init__() (iblrig.scale.scaledata method)": [[203, "iblrig.scale.ScaleData.__init__", false]], "__init__() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.__init__", false]], "__init__() (iblrig.serial_singleton.serialsingletonexception method)": [[206, "iblrig.serial_singleton.SerialSingletonException.__init__", false]], "__init__() (iblrig.tools.ansi method)": [[219, "iblrig.tools.ANSI.__init__", false]], "__init__() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.__init__", false]], "__init__() (iblrig.valve.valve method)": [[240, "iblrig.valve.Valve.__init__", false]], "__init__() (iblrig.valve.valvevalues method)": [[241, "iblrig.valve.ValveValues.__init__", false]], "__init__() (iblrig_tasks._iblrig_tasks_advancedchoiceworld.task.session method)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.__init__", false]], "__init__() (iblrig_tasks._iblrig_tasks_ephyschoiceworld.task.session method)": [[266, "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.__init__", false]], "__init__() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session method)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.__init__", false]], "__init__() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.sessionrelatedblocks method)": [[274, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.__init__", false]], "__init__() (iblrig_tasks._iblrig_tasks_passivechoiceworld.task.session method)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.__init__", false]], "__init__() (iblrig_tasks._iblrig_tasks_trainingphasechoiceworld.task.session method)": [[287, "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.__init__", false]], "__new__() (iblrig.gui.tab_data.column static method)": [[64, "iblrig.gui.tab_data.Column.__new__", false]], "__new__() (iblrig.hardware.bpod static method)": [[123, "iblrig.hardware.Bpod.__new__", false]], "__new__() (iblrig.hardware.softcode method)": [[125, "iblrig.hardware.SOFTCODE.__new__", false]], "__new__() (iblrig.hardware_validation.status method)": [[130, "iblrig.hardware_validation.Status.__new__", false]], "__new__() (iblrig.hardware_validation.validatehardwareerror method)": [[131, "iblrig.hardware_validation.ValidateHardwareError.__new__", false]], "__new__() (iblrig.hifi.hifiexception method)": [[149, "iblrig.hifi.HiFiException.__new__", false]], "__new__() (iblrig.net.auxiliaries static method)": [[160, "iblrig.net.Auxiliaries.__new__", false]], "__new__() (iblrig.serial_singleton.serialsingleton static method)": [[205, "iblrig.serial_singleton.SerialSingleton.__new__", false]], "__new__() (iblrig.serial_singleton.serialsingletonexception method)": [[206, "iblrig.serial_singleton.SerialSingletonException.__new__", false]], "__new__() (iblrig.transfer_experiments.copystate method)": [[231, "iblrig.transfer_experiments.CopyState.__new__", false]], "acceptnavigationrequest() (iblrig.gui.tab_docs.customwebenginepage method)": [[70, "iblrig.gui.tab_docs.CustomWebEnginePage.acceptNavigationRequest", false]], "activechoiceworldsession (class in iblrig.base_choice_world)": [[3, "iblrig.base_choice_world.ActiveChoiceWorldSession", false]], "activechoiceworldtrialdata (class in iblrig.base_choice_world)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData", false]], "add_samples() (iblrig.valve.valvevalues method)": [[241, "iblrig.valve.ValveValues.add_samples", false]], "alyx (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.alyx", false]], "alyx_lab (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.ALYX_LAB", false]], "alyx_reachable() (in module iblrig.tools)": [[220, "iblrig.tools.alyx_reachable", false]], "alyx_url (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.ALYX_URL", false]], "alyx_user (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.ALYX_USER", false]], "alyxobject (class in iblrig.gui.tools)": [[75, "iblrig.gui.tools.AlyxObject", false]], "ambient_module (iblrig.hardware.bpod property)": [[123, "iblrig.hardware.Bpod.ambient_module", false]], "amp_type (iblrig.pydantic_definitions.hardwaresettingssound attribute)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound.AMP_TYPE", false]], "ansi (class in iblrig.tools)": [[219, "iblrig.tools.ANSI", false]], "append_session (iblrig.gui.wizard.rigwizard attribute)": [[118, "iblrig.gui.wizard.RigWizard.append_session", false]], "appendtext() (iblrig.gui.tab_log.tablog method)": [[73, "iblrig.gui.tab_log.TabLog.appendText", false]], "args (iblrig.gui.tools.worker attribute)": [[82, "iblrig.gui.tools.Worker.args", false]], "ask_user() (in module iblrig.tools)": [[221, "iblrig.tools.ask_user", false]], "assert_connect_on_init (iblrig.transfer_experiments.behaviorcopier attribute)": [[230, "iblrig.transfer_experiments.BehaviorCopier.assert_connect_on_init", false]], "assert_connect_on_init (iblrig.transfer_experiments.ephyscopier attribute)": [[232, "iblrig.transfer_experiments.EphysCopier.assert_connect_on_init", false]], "assert_connect_on_init (iblrig.transfer_experiments.sessioncopier attribute)": [[233, "iblrig.transfer_experiments.SessionCopier.assert_connect_on_init", false]], "assert_connect_on_init (iblrig.transfer_experiments.videocopier attribute)": [[234, "iblrig.transfer_experiments.VideoCopier.assert_connect_on_init", false]], "assert_setting() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.assert_setting", false]], "attenuation_db (iblrig.hifi.hifi property)": [[148, "iblrig.hifi.HiFi.attenuation_db", false]], "auxiliaries (class in iblrig.net)": [[160, "iblrig.net.Auxiliaries", false]], "base_parameters_file (iblrig.base_choice_world.biasedchoiceworldsession attribute)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.base_parameters_file", false]], "base_parameters_file (iblrig.base_choice_world.choiceworldsession attribute)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.base_parameters_file", false]], "base_parameters_file (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.base_parameters_file", false]], "basesession (class in iblrig.base_tasks)": [[14, "iblrig.base_tasks.BaseSession", false]], "behaviorcopier (class in iblrig.transfer_experiments)": [[230, "iblrig.transfer_experiments.BehaviorCopier", false]], "biasedchoiceworldsession (class in iblrig.base_choice_world)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession", false]], "biasedchoiceworldtrialdata (class in iblrig.base_choice_world)": [[6, "iblrig.base_choice_world.BiasedChoiceWorldTrialData", false]], "bit_depth (iblrig.hifi.hifi property)": [[148, "iblrig.hifi.HiFi.bit_depth", false]], "block_num (iblrig.base_choice_world.biasedchoiceworldtrialdata attribute)": [[6, "iblrig.base_choice_world.BiasedChoiceWorldTrialData.block_num", false]], "block_trial_num (iblrig.base_choice_world.biasedchoiceworldtrialdata attribute)": [[6, "iblrig.base_choice_world.BiasedChoiceWorldTrialData.block_trial_num", false]], "blue (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.BLUE", false]], "bold (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.BOLD", false]], "bonsai_workflow (iblrig.pydantic_definitions.hardwaresettingsmicrophone attribute)": [[189, "iblrig.pydantic_definitions.HardwareSettingsMicrophone.BONSAI_WORKFLOW", false]], "bonsairecordingmixin (class in iblrig.base_tasks)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin", false]], "bonsaivisualstimulusmixin (class in iblrig.base_tasks)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin", false]], "bpod (class in iblrig.hardware)": [[123, "iblrig.hardware.Bpod", false]], "bpod (iblrig.base_tasks.hasbpod attribute)": [[20, "iblrig.base_tasks.HasBpod.bpod", false]], "bpod_ttl_test_date (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.BPOD_TTL_TEST_DATE", false]], "bpod_ttl_test_status (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.BPOD_TTL_TEST_STATUS", false]], "bpodmixin (class in iblrig.base_tasks)": [[17, "iblrig.base_tasks.BpodMixin", false]], "bunchmodel (class in iblrig.pydantic_definitions)": [[182, "iblrig.pydantic_definitions.BunchModel", false]], "calibrate() (iblrig.frame2ttl.frame2ttl method)": [[49, "iblrig.frame2ttl.Frame2TTL.calibrate", false]], "calibrate() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.calibrate", false]], "calibration_date (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.calibration_date", false]], "calibration_finished (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.calibration_finished", false]], "calibration_range (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.calibration_range", false]], "calibrationplot (class in iblrig.gui.valve)": [[114, "iblrig.gui.valve.CalibrationPlot", false]], "call_bonsai() (in module iblrig.tools)": [[222, "iblrig.tools.call_bonsai", false]], "call_bonsai_async() (in module iblrig.tools)": [[223, "iblrig.tools.call_bonsai_async", false]], "call_git() (in module iblrig.version_management)": [[243, "iblrig.version_management.call_git", false]], "call_subprocesses() (in module iblrig.upgrade_iblrig)": [[237, "iblrig.upgrade_iblrig.call_subprocesses", false]], "can_control_led (iblrig.hardware.bpod attribute)": [[123, "iblrig.hardware.Bpod.can_control_led", false]], "check_for_updates() (in module iblrig.version_management)": [[244, "iblrig.version_management.check_for_updates", false]], "check_sync_pulses() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.check_sync_pulses", false]], "check_training_phase() (iblrig.base_choice_world.trainingchoiceworldsession method)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.check_training_phase", false]], "check_training_phase() (iblrig_tasks._iblrig_tasks_trainingphasechoiceworld.task.session method)": [[287, "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.check_training_phase", false]], "check_upgrade_prerequisites() (in module iblrig.version_management)": [[245, "iblrig.version_management.check_upgrade_prerequisites", false]], "check_uri_match() (in module iblrig.net)": [[162, "iblrig.net.check_uri_match", false]], "choice_delay (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.neuromodulatorchoicetrialdata attribute)": [[272, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.choice_delay", false]], "choice_to_feedback_delay (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session property)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.choice_to_feedback_delay", false]], "choice_world_visual_stimulus() (iblrig.base_tasks.bonsaivisualstimulusmixin method)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin.choice_world_visual_stimulus", false]], "choiceworldsession (class in iblrig.base_choice_world)": [[7, "iblrig.base_choice_world.ChoiceWorldSession", false]], "choiceworldtrialdata (class in iblrig.base_choice_world)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData", false]], "cleanup() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.cleanup", false]], "cleanup_mixin_network() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.cleanup_mixin_network", false]], "clear() (iblrig.gui.tab_log.tablog method)": [[73, "iblrig.gui.tab_log.TabLog.clear", false]], "clear() (iblrig.gui.validation.validatoritem method)": [[112, "iblrig.gui.validation.ValidatorItem.clear", false]], "clear() (iblrig.gui.valve.calibrationplot method)": [[114, "iblrig.gui.valve.CalibrationPlot.clear", false]], "clear_calibration() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.clear_calibration", false]], "clear_crop_callback() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.clear_crop_callback", false]], "clear_data() (iblrig.valve.valvevalues method)": [[241, "iblrig.valve.ValveValues.clear_data", false]], "clear_drop() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.clear_drop", false]], "clear_message_queue() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.clear_message_queue", false]], "clickedwhileactive (iblrig.gui.tools.statefulbutton attribute)": [[81, "iblrig.gui.tools.StatefulButton.clickedWhileActive", false], [81, "id0", false]], "clickedwhileinactive (iblrig.gui.tools.statefulbutton attribute)": [[81, "iblrig.gui.tools.StatefulButton.clickedWhileInactive", false], [81, "id3", false]], "close() (iblrig.gui.splash.splash method)": [[60, "iblrig.gui.splash.Splash.close", false]], "close() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.close", false]], "close() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.close", false]], "close() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.close", false]], "closeevent() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.closeEvent", false]], "closeevent() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.closeEvent", false]], "color (iblrig.gui.frame2ttl.frame2ttlcalibrationtarget property)": [[55, "iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget.color", false]], "column (class in iblrig.gui.tab_data)": [[64, "iblrig.gui.tab_data.Column", false]], "columncount() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.columnCount", false]], "com_bpod (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.COM_BPOD", false]], "com_f2ttl (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.COM_F2TTL", false]], "com_rotary_encoder (iblrig.pydantic_definitions.hardwaresettingsrotaryencoder attribute)": [[190, "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.COM_ROTARY_ENCODER", false]], "com_scale (iblrig.pydantic_definitions.hardwaresettingsscale attribute)": [[191, "iblrig.pydantic_definitions.HardwareSettingsScale.COM_SCALE", false]], "com_sound (iblrig.pydantic_definitions.hardwaresettingssound attribute)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound.COM_SOUND", false]], "communicate() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.communicate", false]], "complete (iblrig.transfer_experiments.copystate attribute)": [[231, "iblrig.transfer_experiments.CopyState.COMPLETE", false]], "compute_adaptive_reward_volume() (in module iblrig.choiceworld)": [[28, "iblrig.choiceworld.compute_adaptive_reward_volume", false]], "compute_end_session_criteria() (iblrig.online_plots.datamodel method)": [[170, "iblrig.online_plots.DataModel.compute_end_session_criteria", false]], "compute_performance() (iblrig.base_choice_world.trainingchoiceworldsession method)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.compute_performance", false]], "compute_reward_time() (iblrig.base_tasks.valvemixin method)": [[26, "iblrig.base_tasks.ValveMixin.compute_reward_time", false]], "config (iblrig.base_tasks.bonsairecordingmixin attribute)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin.config", false]], "config2stub() (iblrig.transfer_experiments.videocopier static method)": [[234, "iblrig.transfer_experiments.VideoCopier.config2stub", false]], "configure_sound_card() (in module iblrig.sound)": [[215, "iblrig.sound.configure_sound_card", false]], "connect() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.connect", false]], "connect() (iblrig.hardware.myrotaryencoder method)": [[124, "iblrig.hardware.MyRotaryEncoder.connect", false]], "connected (iblrig.net.auxiliaries attribute)": [[160, "iblrig.net.Auxiliaries.connected", false]], "contrast (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.contrast", false]], "contrast_set (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.contrast_set", false]], "contrasts_set() (in module iblrig.choiceworld)": [[29, "iblrig.choiceworld.contrasts_set", false]], "controller2model() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.controller2model", false]], "convert_uis() (in module iblrig.gui.tools)": [[84, "iblrig.gui.tools.convert_uis", false]], "copy_collections() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.copy_collections", false]], "copy_folders() (in module iblrig.transfer_experiments)": [[235, "iblrig.transfer_experiments.copy_folders", false]], "copy_snapshots() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.copy_snapshots", false]], "copystate (class in iblrig.transfer_experiments)": [[231, "iblrig.transfer_experiments.CopyState", false]], "copytoclipboard() (iblrig.gui.tab_log.tablog method)": [[73, "iblrig.gui.tab_log.TabLog.copyToClipboard", false]], "create() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.create", false]], "create_bonsai_layout_from_template() (in module iblrig.path_helper)": [[173, "iblrig.path_helper.create_bonsai_layout_from_template", false]], "create_session() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.create_session", false]], "create_video_stub() (iblrig.transfer_experiments.videocopier method)": [[234, "iblrig.transfer_experiments.VideoCopier.create_video_stub", false]], "critical (iblrig.gui.tools.diskspaceindicator property)": [[77, "iblrig.gui.tools.DiskSpaceIndicator.critical", false]], "customwebenginepage (class in iblrig.gui.tab_docs)": [[70, "iblrig.gui.tab_docs.CustomWebEnginePage", false]], "cyan (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.CYAN", false]], "darkcyan (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.DARKCYAN", false]], "data() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.data", false]], "dataframe (iblrig.gui.tools.dataframetablemodel attribute)": [[76, "iblrig.gui.tools.DataFrameTableModel.dataFrame", false]], "dataframetablemodel (class in iblrig.gui.tools)": [[76, "iblrig.gui.tools.DataFrameTableModel", false]], "dataitemdelegate (class in iblrig.gui.tab_data)": [[65, "iblrig.gui.tab_data.DataItemDelegate", false]], "datamodel (class in iblrig.online_plots)": [[170, "iblrig.online_plots.DataModel", false]], "dataworker (class in iblrig.gui.tab_data)": [[66, "iblrig.gui.tab_data.DataWorker", false]], "debias_trial (iblrig.base_choice_world.trainingchoiceworldtrialdata attribute)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData.debias_trial", false]], "default_reward_amount (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.default_reward_amount", false]], "default_reward_amount (iblrig.base_choice_world.trainingchoiceworldsession property)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.default_reward_amount", false]], "define_and_start_state_machine() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.define_and_start_state_machine", false]], "define_harp_sounds_actions() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.define_harp_sounds_actions", false]], "define_rotary_encoder_actions() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.define_rotary_encoder_actions", false]], "define_xonar_sounds_actions() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.define_xonar_sounds_actions", false]], "delay_to_stim_center (iblrig.base_choice_world.habituationchoiceworldtrialdata attribute)": [[10, "iblrig.base_choice_world.HabituationChoiceWorldTrialData.delay_to_stim_center", false]], "device_bpod (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_bpod", false]], "device_cameras (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_cameras", false]], "device_frame2ttl (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_frame2ttl", false]], "device_microphone (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_microphone", false]], "device_rotary_encoder (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_rotary_encoder", false]], "device_scale (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_scale", false]], "device_screen (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_screen", false]], "device_sound (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_sound", false]], "device_valve (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.device_valve", false]], "dim (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.DIM", false]], "dir_path() (in module iblrig.commands)": [[35, "iblrig.commands.dir_path", false]], "disable_behavior_input_ports (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.DISABLE_BEHAVIOR_INPUT_PORTS", false]], "diskspaceindicator (class in iblrig.gui.tools)": [[77, "iblrig.gui.tools.DiskSpaceIndicator", false]], "display_full_jsonable() (iblrig.online_plots.onlineplots method)": [[171, "iblrig.online_plots.OnlinePlots.display_full_jsonable", false]], "display_idx (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.DISPLAY_IDX", false]], "display_scale_stable() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.display_scale_stable", false]], "display_scale_text() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.display_scale_text", false]], "draw_block_len() (in module iblrig.session_creator)": [[211, "iblrig.session_creator.draw_block_len", false]], "draw_contrast() (in module iblrig.misc)": [[151, "iblrig.misc.draw_contrast", false]], "draw_next_trial_info() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.draw_next_trial_info", false]], "draw_next_trial_info() (iblrig.base_choice_world.habituationchoiceworldsession method)": [[9, "iblrig.base_choice_world.HabituationChoiceWorldSession.draw_next_trial_info", false]], "draw_next_trial_info() (iblrig_tasks._iblrig_tasks_advancedchoiceworld.task.session method)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.draw_next_trial_info", false]], "draw_position() (in module iblrig.session_creator)": [[212, "iblrig.session_creator.draw_position", false]], "draw_quiescent_period() (iblrig_tasks._iblrig_tasks_imagingchoiceworld.task.session static method)": [[257, "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.draw_quiescent_period", false]], "draw_reward_amount() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.sessionrelatedblocks method)": [[274, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.draw_reward_amount", false]], "draw_training_contrast() (in module iblrig.choiceworld)": [[30, "iblrig.choiceworld.draw_training_contrast", false]], "drop_cleared (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.drop_cleared", false]], "emptysession (class in iblrig.base_tasks)": [[18, "iblrig.base_tasks.EmptySession", false]], "end (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.END", false]], "ephyscopier (class in iblrig.transfer_experiments)": [[232, "iblrig.transfer_experiments.EphysCopier", false]], "error (iblrig.gui.tools.workersignals attribute)": [[83, "iblrig.gui.tools.WorkerSignals.error", false], [83, "id0", false]], "event_error (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.event_error", false]], "event_reward (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.event_reward", false]], "eventfilter() (iblrig.gui.splash.splash method)": [[60, "iblrig.gui.splash.Splash.eventFilter", false]], "eventfilter() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.eventFilter", false]], "exception (iblrig.hardware_validation.result attribute)": [[129, "iblrig.hardware_validation.Result.exception", false]], "existingfilepath (in module iblrig.pydantic_definitions)": [[183, "iblrig.pydantic_definitions.ExistingFilePath", false]], "exit() (iblrig.base_tasks.oscclient method)": [[22, "iblrig.base_tasks.OSCClient.exit", false]], "exp_ref (iblrig.base_tasks.basesession property)": [[14, "iblrig.base_tasks.BaseSession.exp_ref", false]], "exp_ref (iblrig.base_tasks.networksession attribute)": [[21, "iblrig.base_tasks.NetworkSession.exp_ref", false]], "exp_ref (iblrig.net.expinfo attribute)": [[161, "iblrig.net.ExpInfo.exp_ref", false]], "experiment_description (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.experiment_description", false]], "experiment_description (iblrig.net.expinfo attribute)": [[161, "iblrig.net.ExpInfo.experiment_description", false]], "experiment_description (iblrig.transfer_experiments.behaviorcopier property)": [[230, "iblrig.transfer_experiments.BehaviorCopier.experiment_description", false]], "experiment_description (iblrig.transfer_experiments.sessioncopier property)": [[233, "iblrig.transfer_experiments.SessionCopier.experiment_description", false]], "expinfo (class in iblrig.net)": [[161, "iblrig.net.ExpInfo", false]], "ext_message (iblrig.hardware_validation.result attribute)": [[129, "iblrig.hardware_validation.Result.ext_message", false]], "extra_parser() (iblrig.base_choice_world.choiceworldsession static method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.extra_parser", false]], "extra_parser() (iblrig.base_tasks.basesession static method)": [[14, "iblrig.base_tasks.BaseSession.extra_parser", false]], "extra_parser() (iblrig_tasks._iblrig_tasks_advancedchoiceworld.task.session static method)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.extra_parser", false]], "extra_parser() (iblrig_tasks._iblrig_tasks_ephyschoiceworld.task.session static method)": [[266, "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.extra_parser", false]], "extra_parser() (iblrig_tasks._iblrig_tasks_passivechoiceworld.task.session static method)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.extra_parser", false]], "extra_parser() (iblrig_tasks._iblrig_tasks_trainingchoiceworld.task.session static method)": [[283, "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session.extra_parser", false]], "extra_parser() (iblrig_tasks._iblrig_tasks_trainingphasechoiceworld.task.session static method)": [[287, "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.extra_parser", false]], "extractor_tasks (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.extractor_tasks", false]], "f2ttl_calibration_date (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.F2TTL_CALIBRATION_DATE", false]], "f2ttl_dark_thresh (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.F2TTL_DARK_THRESH", false]], "f2ttl_light_thresh (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.F2TTL_LIGHT_THRESH", false]], "fail (iblrig.hardware_validation.status attribute)": [[130, "iblrig.hardware_validation.Status.FAIL", false]], "file_experiment_description (iblrig.transfer_experiments.sessioncopier property)": [[233, "iblrig.transfer_experiments.SessionCopier.file_experiment_description", false]], "file_hardware_settings (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.file_hardware_settings", false]], "file_iblrig_settings (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.file_iblrig_settings", false]], "file_remote_experiment_description (iblrig.transfer_experiments.sessioncopier property)": [[233, "iblrig.transfer_experiments.SessionCopier.file_remote_experiment_description", false]], "filter_ports() (in module iblrig.serial_singleton)": [[207, "iblrig.serial_singleton.filter_ports", false]], "finalize_copy() (iblrig.transfer_experiments.behaviorcopier method)": [[230, "iblrig.transfer_experiments.BehaviorCopier.finalize_copy", false]], "finalize_copy() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.finalize_copy", false]], "finalized (iblrig.transfer_experiments.copystate attribute)": [[231, "iblrig.transfer_experiments.CopyState.FINALIZED", false]], "finished (iblrig.gui.tools.workersignals attribute)": [[83, "iblrig.gui.tools.WorkerSignals.finished", false], [83, "id3", false]], "float_or_none() (in module iblrig_tasks._iblrig_tasks_trainingchoiceworld.task)": [[284, "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none", false]], "flush() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.flush", false]], "flush() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.flush", false]], "flush() (in module iblrig.commands)": [[36, "iblrig.commands.flush", false]], "fn (iblrig.gui.tools.worker attribute)": [[82, "iblrig.gui.tools.Worker.fn", false]], "format_sound() (in module iblrig.sound)": [[216, "iblrig.sound.format_sound", false]], "fps (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.FPS", false]], "frame2ttl (class in iblrig.frame2ttl)": [[49, "iblrig.frame2ttl.Frame2TTL", false]], "frame2ttlcalibrationdialog (class in iblrig.gui.frame2ttl)": [[54, "iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog", false]], "frame2ttlcalibrationtarget (class in iblrig.gui.frame2ttl)": [[55, "iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget", false]], "frame2ttlmixin (class in iblrig.base_tasks)": [[19, "iblrig.base_tasks.Frame2TTLMixin", false]], "free_reward() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.free_reward", false]], "free_reward_time (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.free_reward_time", false]], "free_reward_time_sec (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.free_reward_time_sec", false]], "free_reward_volume_ul (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.FREE_REWARD_VOLUME_UL", false]], "free_reward_volume_ul (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.free_reward_volume_ul", false]], "get_all_validators() (in module iblrig.hardware_validation)": [[144, "iblrig.hardware_validation.get_all_validators", false]], "get_ambient_sensor_reading() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.get_ambient_sensor_reading", false]], "get_anydesk_id() (in module iblrig.tools)": [[224, "iblrig.tools.get_anydesk_id", false]], "get_biased_probs() (in module iblrig.misc)": [[152, "iblrig.misc.get_biased_probs", false]], "get_branch() (in module iblrig.version_management)": [[246, "iblrig.version_management.get_branch", false]], "get_changelog() (in module iblrig.version_management)": [[247, "iblrig.version_management.get_changelog", false]], "get_commit_hash() (in module iblrig.path_helper)": [[174, "iblrig.path_helper.get_commit_hash", false]], "get_commit_hash() (in module iblrig.version_management)": [[248, "iblrig.version_management.get_commit_hash", false]], "get_detailed_version_string() (in module iblrig.version_management)": [[249, "iblrig.version_management.get_detailed_version_string", false]], "get_exp_info() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.get_exp_info", false]], "get_grams() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.get_grams", false]], "get_graphviz_task() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.get_graphviz_task", false]], "get_inheritors() (in module iblrig.tools)": [[225, "iblrig.tools.get_inheritors", false]], "get_lab_location_dict() (in module iblrig.tools)": [[226, "iblrig.tools.get_lab_location_dict", false]], "get_local_and_remote_paths() (in module iblrig.path_helper)": [[175, "iblrig.path_helper.get_local_and_remote_paths", false]], "get_local_version() (in module iblrig.version_management)": [[250, "iblrig.version_management.get_local_version", false]], "get_module() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.get_module", false]], "get_next_calibration_time() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.get_next_calibration_time", false]], "get_port_events() (in module iblrig.misc)": [[153, "iblrig.misc.get_port_events", false]], "get_port_from_serial_number() (in module iblrig.serial_singleton)": [[208, "iblrig.serial_singleton.get_port_from_serial_number", false]], "get_remote_devices() (in module iblrig.net)": [[163, "iblrig.net.get_remote_devices", false]], "get_remote_devices_file() (in module iblrig.net)": [[164, "iblrig.net.get_remote_devices_file", false]], "get_remote_tags() (in module iblrig.version_management)": [[251, "iblrig.version_management.get_remote_tags", false]], "get_remote_version() (in module iblrig.version_management)": [[252, "iblrig.version_management.get_remote_version", false]], "get_scale_reading() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.get_scale_reading", false]], "get_serial_number_from_port() (in module iblrig.serial_singleton)": [[209, "iblrig.serial_singleton.get_serial_number_from_port", false]], "get_server_communicator() (in module iblrig.net)": [[165, "iblrig.net.get_server_communicator", false]], "get_session() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.get_session", false]], "get_session_path() (in module iblrig.misc)": [[154, "iblrig.misc.get_session_path", false]], "get_session_template() (iblrig_tasks._iblrig_tasks_ephyschoiceworld.task.session static method)": [[266, "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.get_session_template", false]], "get_stable_grams() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.get_stable_grams", false]], "get_state() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.get_state", false]], "get_state_machine_trial() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.get_state_machine_trial", false]], "get_state_machine_trial() (iblrig.base_choice_world.habituationchoiceworldsession method)": [[9, "iblrig.base_choice_world.HabituationChoiceWorldSession.get_state_machine_trial", false]], "get_state_machine_trial() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session method)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.get_state_machine_trial", false]], "get_state_machine_trial() (iblrig_tasks._iblrig_tasks_passivechoiceworld.task.session method)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.get_state_machine_trial", false]], "get_subject_training_info() (iblrig.base_choice_world.trainingchoiceworldsession method)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.get_subject_training_info", false]], "get_subject_training_info() (in module iblrig.choiceworld)": [[31, "iblrig.choiceworld.get_subject_training_info", false]], "get_task_argument_parser() (in module iblrig.misc)": [[155, "iblrig.misc.get_task_argument_parser", false]], "get_task_arguments() (in module iblrig.misc)": [[156, "iblrig.misc.get_task_arguments", false]], "get_task_directory() (iblrig.base_tasks.basesession class method)": [[14, "iblrig.base_tasks.BaseSession.get_task_directory", false]], "get_task_extra_parser() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.get_task_extra_parser", false]], "get_task_file() (iblrig.base_tasks.basesession class method)": [[14, "iblrig.base_tasks.BaseSession.get_task_file", false]], "get_task_parameters() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.get_task_parameters", false]], "getdevices() (iblrig.gui.tools.remotedeviceslistview method)": [[80, "iblrig.gui.tools.RemoteDevicesListView.getDevices", false]], "glob_file_remote_copy_status() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.glob_file_remote_copy_status", false]], "grams (iblrig.scale.scale property)": [[202, "iblrig.scale.Scale.grams", false]], "green (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.GREEN", false]], "habituationchoiceworldsession (class in iblrig.base_choice_world)": [[9, "iblrig.base_choice_world.HabituationChoiceWorldSession", false]], "habituationchoiceworldtrialdata (class in iblrig.base_choice_world)": [[10, "iblrig.base_choice_world.HabituationChoiceWorldTrialData", false]], "handshake() (iblrig.frame2ttl.frame2ttl method)": [[49, "iblrig.frame2ttl.Frame2TTL.handshake", false]], "handshake() (iblrig.hifi.hifi method)": [[148, "iblrig.hifi.HiFi.handshake", false]], "hard_reset (iblrig.transfer_experiments.copystate attribute)": [[231, "iblrig.transfer_experiments.CopyState.HARD_RESET", false]], "hardware_settings (iblrig.gui.wizard.rigwizard property)": [[118, "iblrig.gui.wizard.RigWizard.hardware_settings", false]], "hardware_settings (iblrig.hardware_validation.validator attribute)": [[132, "iblrig.hardware_validation.Validator.hardware_settings", false]], "hardwaresettings (class in iblrig.pydantic_definitions)": [[184, "iblrig.pydantic_definitions.HardwareSettings", false]], "hardwaresettingsbpod (class in iblrig.pydantic_definitions)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod", false]], "hardwaresettingscamera (class in iblrig.pydantic_definitions)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera", false]], "hardwaresettingscameraworkflow (class in iblrig.pydantic_definitions)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow", false]], "hardwaresettingsframe2ttl (class in iblrig.pydantic_definitions)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL", false]], "hardwaresettingsmicrophone (class in iblrig.pydantic_definitions)": [[189, "iblrig.pydantic_definitions.HardwareSettingsMicrophone", false]], "hardwaresettingsrotaryencoder (class in iblrig.pydantic_definitions)": [[190, "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder", false]], "hardwaresettingsscale (class in iblrig.pydantic_definitions)": [[191, "iblrig.pydantic_definitions.HardwareSettingsScale", false]], "hardwaresettingsscreen (class in iblrig.pydantic_definitions)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen", false]], "hardwaresettingssound (class in iblrig.pydantic_definitions)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound", false]], "hardwaresettingsvalve (class in iblrig.pydantic_definitions)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve", false]], "hasbpod (class in iblrig.base_tasks)": [[20, "iblrig.base_tasks.HasBpod", false]], "headerdata() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.headerData", false]], "height (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.HEIGHT", false]], "hidden (iblrig.gui.tab_data.column attribute)": [[64, "iblrig.gui.tab_data.Column.hidden", false]], "hifi (class in iblrig.hifi)": [[148, "iblrig.hifi.HiFi", false]], "hifiexception": [[149, "iblrig.hifi.HiFiException", false]], "iblrig": [[1, "module-iblrig", false]], "iblrig.base_choice_world": [[2, "module-iblrig.base_choice_world", false]], "iblrig.base_tasks": [[13, "module-iblrig.base_tasks", false]], "iblrig.choiceworld": [[27, "module-iblrig.choiceworld", false]], "iblrig.commands": [[34, "module-iblrig.commands", false]], "iblrig.constants": [[43, "module-iblrig.constants", false]], "iblrig.ephys": [[44, "module-iblrig.ephys", false]], "iblrig.frame2ttl": [[48, "module-iblrig.frame2ttl", false]], "iblrig.graphic": [[50, "module-iblrig.graphic", false]], "iblrig.gui": [[52, "module-iblrig.gui", false]], "iblrig.gui.frame2ttl": [[53, "module-iblrig.gui.frame2ttl", false]], "iblrig.gui.resources_rc": [[56, "module-iblrig.gui.resources_rc", false]], "iblrig.gui.splash": [[59, "module-iblrig.gui.splash", false]], "iblrig.gui.tab_about": [[61, "module-iblrig.gui.tab_about", false]], "iblrig.gui.tab_data": [[63, "module-iblrig.gui.tab_data", false]], "iblrig.gui.tab_docs": [[69, "module-iblrig.gui.tab_docs", false]], "iblrig.gui.tab_log": [[72, "module-iblrig.gui.tab_log", false]], "iblrig.gui.tools": [[74, "module-iblrig.gui.tools", false]], "iblrig.gui.ui_frame2ttl": [[85, "module-iblrig.gui.ui_frame2ttl", false]], "iblrig.gui.ui_login": [[87, "module-iblrig.gui.ui_login", false]], "iblrig.gui.ui_splash": [[89, "module-iblrig.gui.ui_splash", false]], "iblrig.gui.ui_tab_about": [[91, "module-iblrig.gui.ui_tab_about", false]], "iblrig.gui.ui_tab_data": [[93, "module-iblrig.gui.ui_tab_data", false]], "iblrig.gui.ui_tab_docs": [[95, "module-iblrig.gui.ui_tab_docs", false]], "iblrig.gui.ui_tab_log": [[97, "module-iblrig.gui.ui_tab_log", false]], "iblrig.gui.ui_tab_session": [[99, "module-iblrig.gui.ui_tab_session", false]], "iblrig.gui.ui_update": [[101, "module-iblrig.gui.ui_update", false]], "iblrig.gui.ui_validation": [[103, "module-iblrig.gui.ui_validation", false]], "iblrig.gui.ui_valve": [[105, "module-iblrig.gui.ui_valve", false]], "iblrig.gui.ui_wizard": [[107, "module-iblrig.gui.ui_wizard", false]], "iblrig.gui.validation": [[109, "module-iblrig.gui.validation", false]], "iblrig.gui.valve": [[113, "module-iblrig.gui.valve", false]], "iblrig.gui.wizard": [[116, "module-iblrig.gui.wizard", false]], "iblrig.hardware": [[122, "module-iblrig.hardware", false]], "iblrig.hardware_validation": [[128, "module-iblrig.hardware_validation", false]], "iblrig.hifi": [[147, "module-iblrig.hifi", false]], "iblrig.misc": [[150, "module-iblrig.misc", false]], "iblrig.net": [[159, "module-iblrig.net", false]], "iblrig.online_plots": [[169, "module-iblrig.online_plots", false]], "iblrig.path_helper": [[172, "module-iblrig.path_helper", false]], "iblrig.pydantic_definitions": [[181, "module-iblrig.pydantic_definitions", false]], "iblrig.raw_data_loaders": [[197, "module-iblrig.raw_data_loaders", false]], "iblrig.rig_component": [[199, "module-iblrig.rig_component", false]], "iblrig.scale": [[201, "module-iblrig.scale", false]], "iblrig.serial_singleton": [[204, "module-iblrig.serial_singleton", false]], "iblrig.session_creator": [[210, "module-iblrig.session_creator", false]], "iblrig.sound": [[214, "module-iblrig.sound", false]], "iblrig.tools": [[218, "module-iblrig.tools", false]], "iblrig.transfer_experiments": [[229, "module-iblrig.transfer_experiments", false]], "iblrig.upgrade_iblrig": [[236, "module-iblrig.upgrade_iblrig", false]], "iblrig.valve": [[239, "module-iblrig.valve", false]], "iblrig.version_management": [[242, "module-iblrig.version_management", false]], "iblrig_local_data_path (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.iblrig_local_data_path", false]], "iblrig_local_subjects_path (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.iblrig_local_subjects_path", false]], "iblrig_remote_data_path (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.iblrig_remote_data_path", false]], "iblrig_remote_subjects_path (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.iblrig_remote_subjects_path", false]], "iblrig_settings (iblrig.gui.wizard.rigwizard property)": [[118, "iblrig.gui.wizard.RigWizard.iblrig_settings", false]], "iblrig_settings (iblrig.hardware_validation.validator attribute)": [[132, "iblrig.hardware_validation.Validator.iblrig_settings", false]], "iblrig_tasks": [[254, "module-iblrig_tasks", false]], "iblrig_tasks._iblrig_tasks_advancedchoiceworld": [[258, "module-iblrig_tasks._iblrig_tasks_advancedChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_advancedchoiceworld.task": [[259, "module-iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_biasedchoiceworld": [[261, "module-iblrig_tasks._iblrig_tasks_biasedChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_biasedchoiceworld.task": [[262, "module-iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_ephyschoiceworld": [[264, "module-iblrig_tasks._iblrig_tasks_ephysChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_ephyschoiceworld.task": [[265, "module-iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_habituationchoiceworld": [[267, "module-iblrig_tasks._iblrig_tasks_habituationChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_habituationchoiceworld.task": [[268, "module-iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_imagingchoiceworld": [[255, "module-iblrig_tasks._iblrig_tasks_ImagingChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_imagingchoiceworld.task": [[256, "module-iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld": [[270, "module-iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task": [[271, "module-iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_passivechoiceworld": [[275, "module-iblrig_tasks._iblrig_tasks_passiveChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_passivechoiceworld.task": [[276, "module-iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_spontaneous": [[278, "module-iblrig_tasks._iblrig_tasks_spontaneous", false]], "iblrig_tasks._iblrig_tasks_spontaneous.task": [[279, "module-iblrig_tasks._iblrig_tasks_spontaneous.task", false]], "iblrig_tasks._iblrig_tasks_trainingchoiceworld": [[281, "module-iblrig_tasks._iblrig_tasks_trainingChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_trainingchoiceworld.task": [[282, "module-iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task", false]], "iblrig_tasks._iblrig_tasks_trainingphasechoiceworld": [[285, "module-iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld", false]], "iblrig_tasks._iblrig_tasks_trainingphasechoiceworld.task": [[286, "module-iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task", false]], "index (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.INDEX", false]], "info (iblrig.hardware_validation.status attribute)": [[130, "iblrig.hardware_validation.Status.INFO", false]], "init_mixin_bonsai_recordings() (iblrig.base_tasks.bonsairecordingmixin method)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin.init_mixin_bonsai_recordings", false]], "init_mixin_bonsai_visual_stimulus() (iblrig.base_tasks.bonsaivisualstimulusmixin method)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin.init_mixin_bonsai_visual_stimulus", false]], "init_mixin_bpod() (iblrig.base_tasks.bpodmixin method)": [[17, "iblrig.base_tasks.BpodMixin.init_mixin_bpod", false]], "init_mixin_frame2ttl() (iblrig.base_tasks.frame2ttlmixin method)": [[19, "iblrig.base_tasks.Frame2TTLMixin.init_mixin_frame2ttl", false]], "init_mixin_network() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.init_mixin_network", false]], "init_mixin_rotary_encoder() (iblrig.base_tasks.rotaryencodermixin method)": [[23, "iblrig.base_tasks.RotaryEncoderMixin.init_mixin_rotary_encoder", false]], "init_mixin_sound() (iblrig.base_tasks.soundmixin method)": [[24, "iblrig.base_tasks.SoundMixin.init_mixin_sound", false]], "init_mixin_valve() (iblrig.base_tasks.valvemixin method)": [[26, "iblrig.base_tasks.ValveMixin.init_mixin_valve", false]], "initialize_experiment() (iblrig.transfer_experiments.ephyscopier method)": [[232, "iblrig.transfer_experiments.EphysCopier.initialize_experiment", false]], "initialize_experiment() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.initialize_experiment", false]], "initialize_experiment() (iblrig.transfer_experiments.videocopier method)": [[234, "iblrig.transfer_experiments.VideoCopier.initialize_experiment", false]], "initialize_scale() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.initialize_scale", false]], "initialized (iblrig.gui.tab_data.dataworker attribute)": [[66, "iblrig.gui.tab_data.DataWorker.initialized", false]], "initstyleoption() (iblrig.gui.tab_data.dataitemdelegate method)": [[65, "iblrig.gui.tab_data.DataItemDelegate.initStyleOption", false]], "install_alyx_token() (in module iblrig.net)": [[166, "iblrig.net.install_alyx_token", false]], "interactive (iblrig.hardware_validation.validator attribute)": [[132, "iblrig.hardware_validation.Validator.interactive", false]], "internet_available() (in module iblrig.tools)": [[227, "iblrig.tools.internet_available", false]], "is_calibrated (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.is_calibrated", false]], "is_connected (iblrig.hardware.bpod property)": [[123, "iblrig.hardware.Bpod.is_connected", false]], "is_connected (iblrig.net.auxiliaries property)": [[160, "iblrig.net.Auxiliaries.is_connected", false]], "is_dirty() (in module iblrig.version_management)": [[253, "iblrig.version_management.is_dirty", false]], "is_hd (iblrig.hifi.hifi property)": [[148, "iblrig.hifi.HiFi.is_hd", false]], "is_mock (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.is_mock", false]], "is_running (iblrig.net.auxiliaries property)": [[160, "iblrig.net.Auxiliaries.is_running", false]], "isactive (iblrig.gui.tools.statefulbutton attribute)": [[81, "iblrig.gui.tools.StatefulButton.isActive", false]], "isloggedin (iblrig.gui.tools.alyxobject attribute)": [[75, "iblrig.gui.tools.AlyxObject.isLoggedIn", false]], "isloggedin (iblrig.gui.tools.alyxobject property)": [[75, "id0", false]], "item_finished (iblrig.gui.validation.systemvalidationdialog attribute)": [[111, "iblrig.gui.validation.SystemValidationDialog.item_finished", false]], "item_result (iblrig.gui.validation.systemvalidationdialog attribute)": [[111, "iblrig.gui.validation.SystemValidationDialog.item_result", false]], "item_started (iblrig.gui.validation.systemvalidationdialog attribute)": [[111, "iblrig.gui.validation.SystemValidationDialog.item_started", false]], "items() (iblrig.pydantic_definitions.bunchmodel method)": [[182, "iblrig.pydantic_definitions.BunchModel.items", false]], "iterate_collection() (in module iblrig.path_helper)": [[176, "iblrig.path_helper.iterate_collection", false]], "iterate_previous_sessions() (in module iblrig.path_helper)": [[177, "iblrig.path_helper.iterate_previous_sessions", false]], "iti_reward (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.iti_reward", false]], "keys() (iblrig.pydantic_definitions.bunchmodel method)": [[182, "iblrig.pydantic_definitions.BunchModel.keys", false]], "kwargs (iblrig.gui.tools.worker attribute)": [[82, "iblrig.gui.tools.Worker.kwargs", false]], "lazyloadcomplete (iblrig.gui.tab_data.dataworker attribute)": [[66, "iblrig.gui.tab_data.DataWorker.lazyLoadComplete", false]], "lazyloadstatus() (iblrig.gui.tab_data.dataworker method)": [[66, "iblrig.gui.tab_data.DataWorker.lazyLoadStatus", false]], "lineeditalyxuser (class in iblrig.gui.tools)": [[78, "iblrig.gui.tools.LineEditAlyxUser", false]], "listen() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.listen", false]], "load() (iblrig.hifi.hifi method)": [[148, "iblrig.hifi.HiFi.load", false]], "load_pydantic_yaml() (in module iblrig.path_helper)": [[178, "iblrig.path_helper.load_pydantic_yaml", false]], "load_task_jsonable() (in module iblrig.raw_data_loaders)": [[198, "iblrig.raw_data_loaders.load_task_jsonable", false]], "log_results (iblrig.hardware_validation.validator attribute)": [[132, "iblrig.hardware_validation.Validator.log_results", false]], "loggedin (iblrig.gui.tools.alyxobject attribute)": [[75, "iblrig.gui.tools.AlyxObject.loggedIn", false], [75, "id1", false]], "loggedout (iblrig.gui.tools.alyxobject attribute)": [[75, "iblrig.gui.tools.AlyxObject.loggedOut", false], [75, "id4", false]], "logger (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.logger", false]], "login() (iblrig.gui.tools.alyxobject method)": [[75, "iblrig.gui.tools.AlyxObject.logIn", false]], "login() (iblrig.gui.tools.lineeditalyxuser method)": [[78, "iblrig.gui.tools.LineEditAlyxUser.logIn", false]], "login() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.login", false]], "loginfailed (iblrig.gui.tools.alyxobject attribute)": [[75, "iblrig.gui.tools.AlyxObject.loginFailed", false], [75, "id7", false]], "loginwindow (class in iblrig.gui.wizard)": [[117, "iblrig.gui.wizard.LoginWindow", false]], "logout() (iblrig.gui.tools.alyxobject method)": [[75, "iblrig.gui.tools.AlyxObject.logOut", false]], "logout() (iblrig.gui.wizard.rigwizardmodel method)": [[119, "iblrig.gui.wizard.RigWizardModel.logout", false]], "main() (in module iblrig.gui.wizard)": [[121, "iblrig.gui.wizard.main", false]], "main_sync (iblrig.net.expinfo attribute)": [[161, "iblrig.net.ExpInfo.main_sync", false]], "main_sync (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.MAIN_SYNC", false]], "make_ephyscw_pc() (in module iblrig.session_creator)": [[213, "iblrig.session_creator.make_ephyscw_pc", false]], "make_experiment_description_dict() (iblrig.base_tasks.basesession static method)": [[14, "iblrig.base_tasks.BaseSession.make_experiment_description_dict", false]], "make_sound() (in module iblrig.sound)": [[217, "iblrig.sound.make_sound", false]], "master (iblrig.net.expinfo attribute)": [[161, "iblrig.net.ExpInfo.master", false]], "max_envelope_samples (iblrig.hifi.hifi property)": [[148, "iblrig.hifi.HiFi.max_envelope_samples", false]], "max_samples_per_waveform (iblrig.hifi.hifi property)": [[148, "iblrig.hifi.HiFi.max_samples_per_waveform", false]], "message (iblrig.hardware_validation.result attribute)": [[129, "iblrig.hardware_validation.Result.message", false]], "mock() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.mock", false]], "mock() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.mock", false]], "mode (iblrig.scale.scaledata attribute)": [[203, "iblrig.scale.ScaleData.mode", false]], "model2view() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.model2view", false]], "model_computed_fields (iblrig.base_choice_world.activechoiceworldtrialdata attribute)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData.model_computed_fields", false]], "model_computed_fields (iblrig.base_choice_world.biasedchoiceworldtrialdata attribute)": [[6, "iblrig.base_choice_world.BiasedChoiceWorldTrialData.model_computed_fields", false]], "model_computed_fields (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.model_computed_fields", false]], "model_computed_fields (iblrig.base_choice_world.habituationchoiceworldtrialdata attribute)": [[10, "iblrig.base_choice_world.HabituationChoiceWorldTrialData.model_computed_fields", false]], "model_computed_fields (iblrig.base_choice_world.trainingchoiceworldtrialdata attribute)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.bunchmodel attribute)": [[182, "iblrig.pydantic_definitions.BunchModel.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingscameraworkflow attribute)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsmicrophone attribute)": [[189, "iblrig.pydantic_definitions.HardwareSettingsMicrophone.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsrotaryencoder attribute)": [[190, "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsscale attribute)": [[191, "iblrig.pydantic_definitions.HardwareSettingsScale.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingssound attribute)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.model_computed_fields", false]], "model_computed_fields (iblrig.pydantic_definitions.trialdatamodel attribute)": [[196, "iblrig.pydantic_definitions.TrialDataModel.model_computed_fields", false]], "model_computed_fields (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.neuromodulatorchoicetrialdata attribute)": [[272, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.model_computed_fields", false]], "model_config (iblrig.base_choice_world.activechoiceworldtrialdata attribute)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData.model_config", false]], "model_config (iblrig.base_choice_world.biasedchoiceworldtrialdata attribute)": [[6, "iblrig.base_choice_world.BiasedChoiceWorldTrialData.model_config", false]], "model_config (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.model_config", false]], "model_config (iblrig.base_choice_world.habituationchoiceworldtrialdata attribute)": [[10, "iblrig.base_choice_world.HabituationChoiceWorldTrialData.model_config", false]], "model_config (iblrig.base_choice_world.trainingchoiceworldtrialdata attribute)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData.model_config", false]], "model_config (iblrig.pydantic_definitions.bunchmodel attribute)": [[182, "iblrig.pydantic_definitions.BunchModel.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingscameraworkflow attribute)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsmicrophone attribute)": [[189, "iblrig.pydantic_definitions.HardwareSettingsMicrophone.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsrotaryencoder attribute)": [[190, "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsscale attribute)": [[191, "iblrig.pydantic_definitions.HardwareSettingsScale.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingssound attribute)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound.model_config", false]], "model_config (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.model_config", false]], "model_config (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.model_config", false]], "model_config (iblrig.pydantic_definitions.trialdatamodel attribute)": [[196, "iblrig.pydantic_definitions.TrialDataModel.model_config", false]], "model_config (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.neuromodulatorchoicetrialdata attribute)": [[272, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.model_config", false]], "model_fields (iblrig.base_choice_world.activechoiceworldtrialdata attribute)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData.model_fields", false]], "model_fields (iblrig.base_choice_world.biasedchoiceworldtrialdata attribute)": [[6, "iblrig.base_choice_world.BiasedChoiceWorldTrialData.model_fields", false]], "model_fields (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.model_fields", false]], "model_fields (iblrig.base_choice_world.habituationchoiceworldtrialdata attribute)": [[10, "iblrig.base_choice_world.HabituationChoiceWorldTrialData.model_fields", false]], "model_fields (iblrig.base_choice_world.trainingchoiceworldtrialdata attribute)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData.model_fields", false]], "model_fields (iblrig.pydantic_definitions.bunchmodel attribute)": [[182, "iblrig.pydantic_definitions.BunchModel.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingscameraworkflow attribute)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsframe2ttl attribute)": [[188, "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsmicrophone attribute)": [[189, "iblrig.pydantic_definitions.HardwareSettingsMicrophone.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsrotaryencoder attribute)": [[190, "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsscale attribute)": [[191, "iblrig.pydantic_definitions.HardwareSettingsScale.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingssound attribute)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound.model_fields", false]], "model_fields (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.model_fields", false]], "model_fields (iblrig.pydantic_definitions.rigsettings attribute)": [[195, "iblrig.pydantic_definitions.RigSettings.model_fields", false]], "model_fields (iblrig.pydantic_definitions.trialdatamodel attribute)": [[196, "iblrig.pydantic_definitions.TrialDataModel.model_fields", false]], "model_fields (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.neuromodulatorchoicetrialdata attribute)": [[272, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.model_fields", false]], "module": [[1, "module-iblrig", false], [2, "module-iblrig.base_choice_world", false], [13, "module-iblrig.base_tasks", false], [27, "module-iblrig.choiceworld", false], [34, "module-iblrig.commands", false], [43, "module-iblrig.constants", false], [44, "module-iblrig.ephys", false], [48, "module-iblrig.frame2ttl", false], [50, "module-iblrig.graphic", false], [52, "module-iblrig.gui", false], [53, "module-iblrig.gui.frame2ttl", false], [56, "module-iblrig.gui.resources_rc", false], [59, "module-iblrig.gui.splash", false], [61, "module-iblrig.gui.tab_about", false], [63, "module-iblrig.gui.tab_data", false], [69, "module-iblrig.gui.tab_docs", false], [72, "module-iblrig.gui.tab_log", false], [74, "module-iblrig.gui.tools", false], [85, "module-iblrig.gui.ui_frame2ttl", false], [87, "module-iblrig.gui.ui_login", false], [89, "module-iblrig.gui.ui_splash", false], [91, "module-iblrig.gui.ui_tab_about", false], [93, "module-iblrig.gui.ui_tab_data", false], [95, "module-iblrig.gui.ui_tab_docs", false], [97, "module-iblrig.gui.ui_tab_log", false], [99, "module-iblrig.gui.ui_tab_session", false], [101, "module-iblrig.gui.ui_update", false], [103, "module-iblrig.gui.ui_validation", false], [105, "module-iblrig.gui.ui_valve", false], [107, "module-iblrig.gui.ui_wizard", false], [109, "module-iblrig.gui.validation", false], [113, "module-iblrig.gui.valve", false], [116, "module-iblrig.gui.wizard", false], [122, "module-iblrig.hardware", false], [128, "module-iblrig.hardware_validation", false], [147, "module-iblrig.hifi", false], [150, "module-iblrig.misc", false], [159, "module-iblrig.net", false], [169, "module-iblrig.online_plots", false], [172, "module-iblrig.path_helper", false], [181, "module-iblrig.pydantic_definitions", false], [197, "module-iblrig.raw_data_loaders", false], [199, "module-iblrig.rig_component", false], [201, "module-iblrig.scale", false], [204, "module-iblrig.serial_singleton", false], [210, "module-iblrig.session_creator", false], [214, "module-iblrig.sound", false], [218, "module-iblrig.tools", false], [229, "module-iblrig.transfer_experiments", false], [236, "module-iblrig.upgrade_iblrig", false], [239, "module-iblrig.valve", false], [242, "module-iblrig.version_management", false], [254, "module-iblrig_tasks", false], [255, "module-iblrig_tasks._iblrig_tasks_ImagingChoiceWorld", false], [256, "module-iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task", false], [258, "module-iblrig_tasks._iblrig_tasks_advancedChoiceWorld", false], [259, "module-iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task", false], [261, "module-iblrig_tasks._iblrig_tasks_biasedChoiceWorld", false], [262, "module-iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task", false], [264, "module-iblrig_tasks._iblrig_tasks_ephysChoiceWorld", false], [265, "module-iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task", false], [267, "module-iblrig_tasks._iblrig_tasks_habituationChoiceWorld", false], [268, "module-iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task", false], [270, "module-iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld", false], [271, "module-iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task", false], [275, "module-iblrig_tasks._iblrig_tasks_passiveChoiceWorld", false], [276, "module-iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task", false], [278, "module-iblrig_tasks._iblrig_tasks_spontaneous", false], [279, "module-iblrig_tasks._iblrig_tasks_spontaneous.task", false], [281, "module-iblrig_tasks._iblrig_tasks_trainingChoiceWorld", false], [282, "module-iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task", false], [285, "module-iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld", false], [286, "module-iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task", false]], "ms2ul() (iblrig.valve.valvevalues method)": [[241, "iblrig.valve.ValveValues.ms2ul", false]], "myrotaryencoder (class in iblrig.hardware)": [[124, "iblrig.hardware.MyRotaryEncoder", false]], "name (iblrig.gui.tab_data.column attribute)": [[64, "iblrig.gui.tab_data.Column.name", false]], "name (iblrig.hardware_validation.validator property)": [[132, "iblrig.hardware_validation.Validator.name", false]], "networksession (class in iblrig.base_tasks)": [[21, "iblrig.base_tasks.NetworkSession", false]], "neuromodulatorchoicetrialdata (class in iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task)": [[272, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData", false]], "neuropixel24_micromanipulator_coordinates() (in module iblrig.ephys)": [[45, "iblrig.ephys.neuropixel24_micromanipulator_coordinates", false]], "new_block() (iblrig.base_choice_world.biasedchoiceworldsession method)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.new_block", false]], "new_block() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.sessionrelatedblocks method)": [[274, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.new_block", false]], "new_calibration_open_times (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.new_calibration_open_times", false]], "new_subject_details (iblrig.gui.wizard.rigwizard attribute)": [[118, "iblrig.gui.wizard.RigWizard.new_subject_details", false]], "next_trial() (iblrig.base_choice_world.biasedchoiceworldsession method)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.next_trial", false]], "next_trial() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.next_trial", false]], "next_trial() (iblrig.base_choice_world.habituationchoiceworldsession method)": [[9, "iblrig.base_choice_world.HabituationChoiceWorldSession.next_trial", false]], "next_trial() (iblrig.base_choice_world.trainingchoiceworldsession method)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.next_trial", false]], "next_trial() (iblrig_tasks._iblrig_tasks_advancedchoiceworld.task.session method)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.next_trial", false]], "next_trial() (iblrig_tasks._iblrig_tasks_ephyschoiceworld.task.session method)": [[266, "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.next_trial", false]], "next_trial() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session method)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.next_trial", false]], "next_trial() (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.sessionrelatedblocks method)": [[274, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks.next_trial", false]], "next_trial() (iblrig_tasks._iblrig_tasks_passivechoiceworld.task.session method)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.next_trial", false]], "not_registered (iblrig.transfer_experiments.copystate attribute)": [[231, "iblrig.transfer_experiments.CopyState.NOT_REGISTERED", false]], "ntrials (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.ntrials", false]], "ntrials_correct (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.ntrials_correct", false]], "ntrials_engaged (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.ntrials_engaged", false]], "ntrials_nan (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.ntrials_nan", false]], "numinput() (in module iblrig.graphic)": [[51, "iblrig.graphic.numinput", false]], "omit_feedback (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.neuromodulatorchoicetrialdata attribute)": [[272, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData.omit_feedback", false]], "omit_feedback (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session property)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.omit_feedback", false]], "on_item_finished() (iblrig.gui.validation.systemvalidationdialog method)": [[111, "iblrig.gui.validation.SystemValidationDialog.on_item_finished", false]], "on_item_result() (iblrig.gui.validation.systemvalidationdialog method)": [[111, "iblrig.gui.validation.SystemValidationDialog.on_item_result", false]], "on_item_started() (iblrig.gui.validation.systemvalidationdialog method)": [[111, "iblrig.gui.validation.SystemValidationDialog.on_item_started", false]], "one (iblrig.base_tasks.basesession property)": [[14, "iblrig.base_tasks.BaseSession.one", false]], "one (iblrig.base_tasks.networksession property)": [[21, "iblrig.base_tasks.NetworkSession.one", false]], "ongetanydeskresult() (iblrig.gui.tab_about.tababout method)": [[62, "iblrig.gui.tab_about.TabAbout.onGetAnydeskResult", false]], "online_std() (in module iblrig.misc)": [[157, "iblrig.misc.online_std", false]], "onlineplots (class in iblrig.online_plots)": [[171, "iblrig.online_plots.OnlinePlots", false]], "open() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.open", false]], "open_times_ms (iblrig.valve.valvevalues property)": [[241, "iblrig.valve.ValveValues.open_times_ms", false]], "open_valve() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.open_valve", false]], "osc_protocol (iblrig.base_tasks.oscclient attribute)": [[22, "iblrig.base_tasks.OSCClient.OSC_PROTOCOL", false]], "oscclient (class in iblrig.base_tasks)": [[22, "iblrig.base_tasks.OSCClient", false]], "output (iblrig.pydantic_definitions.hardwaresettingssound attribute)": [[193, "iblrig.pydantic_definitions.HardwareSettingsSound.OUTPUT", false]], "pass (iblrig.hardware_validation.status attribute)": [[130, "iblrig.hardware_validation.Status.PASS", false]], "patch_settings() (in module iblrig.path_helper)": [[179, "iblrig.path_helper.patch_settings", false]], "pause() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.pause", false]], "pause_duration (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.pause_duration", false]], "pend (iblrig.hardware_validation.status attribute)": [[130, "iblrig.hardware_validation.Status.PEND", false]], "pending (iblrig.transfer_experiments.copystate attribute)": [[231, "iblrig.transfer_experiments.CopyState.PENDING", false]], "percent_correct (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.percent_correct", false]], "percent_error (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.percent_error", false]], "play() (iblrig.hifi.hifi method)": [[148, "iblrig.hifi.HiFi.play", false]], "play_noise (iblrig.hardware.softcode attribute)": [[125, "iblrig.hardware.SOFTCODE.PLAY_NOISE", false]], "play_tone (iblrig.hardware.softcode attribute)": [[125, "iblrig.hardware.SOFTCODE.PLAY_TONE", false]], "port (iblrig.hardware_validation.validatorbpod property)": [[135, "iblrig.hardware_validation.ValidatorBpod.port", false]], "port (iblrig.hardware_validation.validatorframe2ttl property)": [[137, "iblrig.hardware_validation.ValidatorFrame2TTL.port", false]], "port (iblrig.hardware_validation.validatorrotaryencodermodule property)": [[140, "iblrig.hardware_validation.ValidatorRotaryEncoderModule.port", false]], "port (iblrig.hardware_validation.validatorserial property)": [[141, "iblrig.hardware_validation.ValidatorSerial.port", false]], "port (iblrig.hardware_validation.validatorsound property)": [[142, "iblrig.hardware_validation.ValidatorSound.port", false]], "port (iblrig.serial_singleton.serialsingleton property)": [[205, "iblrig.serial_singleton.SerialSingleton.port", false]], "port_info (iblrig.hardware_validation.validatorserial property)": [[141, "iblrig.hardware_validation.ValidatorSerial.port_info", false]], "port_properties (iblrig.hardware_validation.validatorbpod attribute)": [[135, "iblrig.hardware_validation.ValidatorBpod.port_properties", false]], "port_properties (iblrig.hardware_validation.validatorrotaryencodermodule attribute)": [[140, "iblrig.hardware_validation.ValidatorRotaryEncoderModule.port_properties", false]], "port_properties (iblrig.hardware_validation.validatorserial attribute)": [[141, "iblrig.hardware_validation.ValidatorSerial.port_properties", false]], "position (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.position", false]], "position (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.position", false]], "preallocate_dataframe() (iblrig.pydantic_definitions.trialdatamodel class method)": [[196, "iblrig.pydantic_definitions.TrialDataModel.preallocate_dataframe", false]], "prepare_ephys_session() (in module iblrig.ephys)": [[46, "iblrig.ephys.prepare_ephys_session", false]], "prepare_ephys_session_cmd() (in module iblrig.ephys)": [[47, "iblrig.ephys.prepare_ephys_session_cmd", false]], "pretty_name (iblrig.rig_component.rigcomponent property)": [[200, "iblrig.rig_component.RigComponent.pretty_name", false]], "previous_subject (iblrig.gui.wizard.rigwizard attribute)": [[118, "iblrig.gui.wizard.RigWizard.previous_subject", false]], "probability_set (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.probability_set", false]], "procedures (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.procedures", false]], "process() (iblrig.hardware_validation.validator method)": [[132, "iblrig.hardware_validation.Validator.process", false]], "progress (iblrig.gui.tools.workersignals attribute)": [[83, "iblrig.gui.tools.WorkerSignals.progress", false], [83, "id6", false]], "projects (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.projects", false]], "protocol_name (iblrig.base_choice_world.biasedchoiceworldsession attribute)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.protocol_name", false]], "protocol_name (iblrig.base_choice_world.habituationchoiceworldsession attribute)": [[9, "iblrig.base_choice_world.HabituationChoiceWorldSession.protocol_name", false]], "protocol_name (iblrig.base_choice_world.trainingchoiceworldsession attribute)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.protocol_name", false]], "protocol_name (iblrig.base_tasks.basesession property)": [[14, "iblrig.base_tasks.BaseSession.protocol_name", false]], "protocol_name (iblrig.base_tasks.emptysession attribute)": [[18, "iblrig.base_tasks.EmptySession.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_advancedchoiceworld.task.session attribute)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_ephyschoiceworld.task.session attribute)": [[266, "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_imagingchoiceworld.task.session attribute)": [[257, "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session attribute)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_passivechoiceworld.task.session attribute)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_spontaneous.task.session attribute)": [[280, "iblrig_tasks._iblrig_tasks_spontaneous.task.Session.protocol_name", false]], "protocol_name (iblrig_tasks._iblrig_tasks_trainingphasechoiceworld.task.session attribute)": [[287, "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session.protocol_name", false]], "pulse_valve() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.pulse_valve", false]], "pulse_valve() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.pulse_valve", false]], "pulse_valve_repeatedly() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.pulse_valve_repeatedly", false]], "purple (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.PURPLE", false]], "push() (iblrig.hifi.hifi method)": [[148, "iblrig.hifi.HiFi.push", false]], "push() (iblrig.net.auxiliaries method)": [[160, "iblrig.net.Auxiliaries.push", false]], "qcleanupresources() (in module iblrig.gui.resources_rc)": [[57, "iblrig.gui.resources_rc.qCleanupResources", false]], "qinitresources() (in module iblrig.gui.resources_rc)": [[58, "iblrig.gui.resources_rc.qInitResources", false]], "query() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.query", false]], "query_line() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.query_line", false]], "quiescent_period (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.quiescent_period", false]], "quiescent_period (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.quiescent_period", false]], "raise_fail_as_exception (iblrig.hardware_validation.validator attribute)": [[132, "iblrig.hardware_validation.Validator.raise_fail_as_exception", false]], "read() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.read", false]], "read_stdin() (in module iblrig.net)": [[167, "iblrig.net.read_stdin", false]], "read_task_parameter_files() (iblrig.base_tasks.basesession class method)": [[14, "iblrig.base_tasks.BaseSession.read_task_parameter_files", false]], "recording (iblrig.pydantic_definitions.hardwaresettingscameraworkflow attribute)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.recording", false]], "red (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.RED", false]], "refresh_rate (iblrig.net.auxiliaries attribute)": [[160, "iblrig.net.Auxiliaries.refresh_rate", false]], "register_softcodes() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.register_softcodes", false]], "register_to_alyx() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.register_to_alyx", false]], "remote_experiment_description_stub (iblrig.transfer_experiments.sessioncopier property)": [[233, "iblrig.transfer_experiments.SessionCopier.remote_experiment_description_stub", false]], "remote_rigs (iblrig.base_tasks.networksession attribute)": [[21, "iblrig.base_tasks.NetworkSession.remote_rigs", false]], "remote_session_path (iblrig.transfer_experiments.sessioncopier property)": [[233, "iblrig.transfer_experiments.SessionCopier.remote_session_path", false]], "remotedevicesitemmodel (class in iblrig.gui.tools)": [[79, "iblrig.gui.tools.RemoteDevicesItemModel", false]], "remotedeviceslistview (class in iblrig.gui.tools)": [[80, "iblrig.gui.tools.RemoteDevicesListView", false]], "remove_local_sessions() (in module iblrig.commands)": [[37, "iblrig.commands.remove_local_sessions", false]], "resizemode (iblrig.gui.tab_data.column attribute)": [[64, "iblrig.gui.tab_data.Column.resizeMode", false]], "response_received (iblrig.net.auxiliaries attribute)": [[160, "iblrig.net.Auxiliaries.response_received", false]], "response_side (iblrig.base_choice_world.activechoiceworldtrialdata attribute)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData.response_side", false]], "response_side (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.response_side", false]], "response_time (iblrig.base_choice_world.activechoiceworldtrialdata attribute)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData.response_time", false]], "response_time (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.response_time", false]], "restart_com_port() (in module iblrig.hardware)": [[126, "iblrig.hardware.restart_com_port", false]], "result (class in iblrig.hardware_validation)": [[129, "iblrig.hardware_validation.Result", false]], "result (iblrig.gui.tools.workersignals attribute)": [[83, "iblrig.gui.tools.WorkerSignals.result", false], [83, "id9", false]], "retranslateui() (iblrig.gui.ui_frame2ttl.ui_frame2ttl method)": [[86, "iblrig.gui.ui_frame2ttl.Ui_frame2ttl.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_login.ui_login method)": [[88, "iblrig.gui.ui_login.Ui_login.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_splash.ui_splash method)": [[90, "iblrig.gui.ui_splash.Ui_splash.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_tab_about.ui_tababout method)": [[92, "iblrig.gui.ui_tab_about.Ui_TabAbout.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_tab_data.ui_tabdata method)": [[94, "iblrig.gui.ui_tab_data.Ui_TabData.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_tab_docs.ui_tabdocs method)": [[96, "iblrig.gui.ui_tab_docs.Ui_TabDocs.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_tab_log.ui_tablog method)": [[98, "iblrig.gui.ui_tab_log.Ui_TabLog.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_tab_session.ui_tabsession method)": [[100, "iblrig.gui.ui_tab_session.Ui_tabSession.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_update.ui_update method)": [[102, "iblrig.gui.ui_update.Ui_update.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_validation.ui_validation method)": [[104, "iblrig.gui.ui_validation.Ui_validation.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_valve.ui_valve method)": [[106, "iblrig.gui.ui_valve.Ui_valve.retranslateUi", false]], "retranslateui() (iblrig.gui.ui_wizard.ui_wizard method)": [[108, "iblrig.gui.ui_wizard.Ui_wizard.retranslateUi", false]], "reward_amount (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.reward_amount", false]], "reward_amount (iblrig_tasks._iblrig_tasks_advancedchoiceworld.task.session property)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session.reward_amount", false]], "reward_time (iblrig.base_choice_world.choiceworldsession property)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.reward_time", false]], "reward_valve_time (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.reward_valve_time", false]], "rig_name (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.RIG_NAME", false]], "rig_version (iblrig.net.expinfo attribute)": [[161, "iblrig.net.ExpInfo.rig_version", false]], "rigcomponent (class in iblrig.rig_component)": [[200, "iblrig.rig_component.RigComponent", false]], "rigsettings (class in iblrig.pydantic_definitions)": [[195, "iblrig.pydantic_definitions.RigSettings", false]], "rigwizard (class in iblrig.gui.wizard)": [[118, "iblrig.gui.wizard.RigWizard", false]], "rigwizardmodel (class in iblrig.gui.wizard)": [[119, "iblrig.gui.wizard.RigWizardModel", false]], "rotary_encoder (iblrig.hardware.bpod property)": [[123, "iblrig.hardware.Bpod.rotary_encoder", false]], "rotary_encoder_bpod_port (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.ROTARY_ENCODER_BPOD_PORT", false]], "rotaryencodermixin (class in iblrig.base_tasks)": [[23, "iblrig.base_tasks.RotaryEncoderMixin", false]], "rowcount() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.rowCount", false]], "run() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.run", false]], "run() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.run", false]], "run() (iblrig.gui.tab_data.dataworker method)": [[66, "iblrig.gui.tab_data.DataWorker.run", false]], "run() (iblrig.gui.tools.worker method)": [[82, "iblrig.gui.tools.Worker.run", false], [82, "id0", false]], "run() (iblrig.gui.validation.systemvalidationdialog method)": [[111, "iblrig.gui.validation.SystemValidationDialog.run", false]], "run() (iblrig.hardware_validation.validator method)": [[132, "iblrig.hardware_validation.Validator.run", false]], "run() (iblrig.online_plots.onlineplots method)": [[171, "iblrig.online_plots.OnlinePlots.run", false]], "run() (iblrig.transfer_experiments.sessioncopier method)": [[233, "iblrig.transfer_experiments.SessionCopier.run", false]], "run_all_validators() (in module iblrig.hardware_validation)": [[145, "iblrig.hardware_validation.run_all_validators", false]], "run_all_validators_cli() (in module iblrig.hardware_validation)": [[146, "iblrig.hardware_validation.run_all_validators_cli", false]], "run_passive_visual_stim() (iblrig.base_tasks.bonsaivisualstimulusmixin method)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin.run_passive_visual_stim", false]], "run_subprocess() (iblrig.gui.validation.systemvalidationdialog method)": [[111, "iblrig.gui.validation.SystemValidationDialog.run_subprocess", false]], "sample() (iblrig.frame2ttl.frame2ttl method)": [[49, "iblrig.frame2ttl.Frame2TTL.sample", false]], "sampling_rate_hz (iblrig.hifi.hifi property)": [[148, "iblrig.hifi.HiFi.sampling_rate_hz", false]], "save() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.save", false]], "save_pydantic_yaml() (in module iblrig.path_helper)": [[180, "iblrig.path_helper.save_pydantic_yaml", false]], "save_task_parameters_to_json_file() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.save_task_parameters_to_json_file", false]], "save_trial_data_to_json() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.save_trial_data_to_json", false]], "scale (class in iblrig.scale)": [[202, "iblrig.scale.Scale", false]], "scale (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.scale", false]], "scale_initialized (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.scale_initialized", false]], "scale_stable_changed (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.scale_stable_changed", false]], "scale_text_changed (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.scale_text_changed", false]], "scaledata (class in iblrig.scale)": [[203, "iblrig.scale.ScaleData", false]], "screen_freq_target (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.SCREEN_FREQ_TARGET", false]], "screen_freq_test_date (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.SCREEN_FREQ_TEST_DATE", false]], "screen_freq_test_status (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.SCREEN_FREQ_TEST_STATUS", false]], "screen_lux_date (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.SCREEN_LUX_DATE", false]], "screen_lux_value (iblrig.pydantic_definitions.hardwaresettingsscreen attribute)": [[192, "iblrig.pydantic_definitions.HardwareSettingsScreen.SCREEN_LUX_VALUE", false]], "sectionwidth (iblrig.gui.tab_data.column attribute)": [[64, "iblrig.gui.tab_data.Column.sectionWidth", false]], "send2bonsai() (iblrig.base_tasks.oscclient method)": [[22, "iblrig.base_tasks.OSCClient.send2bonsai", false]], "send_spacers() (iblrig.base_tasks.bpodmixin method)": [[17, "iblrig.base_tasks.BpodMixin.send_spacers", false]], "send_trial_info_to_bonsai() (iblrig.base_tasks.bonsaivisualstimulusmixin method)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin.send_trial_info_to_bonsai", false]], "serial_queries (iblrig.hardware_validation.validatorbpod attribute)": [[135, "iblrig.hardware_validation.ValidatorBpod.serial_queries", false]], "serial_queries (iblrig.hardware_validation.validatorframe2ttl attribute)": [[137, "iblrig.hardware_validation.ValidatorFrame2TTL.serial_queries", false]], "serial_queries (iblrig.hardware_validation.validatorrotaryencodermodule attribute)": [[140, "iblrig.hardware_validation.ValidatorRotaryEncoderModule.serial_queries", false]], "serial_queries (iblrig.hardware_validation.validatorserial attribute)": [[141, "iblrig.hardware_validation.ValidatorSerial.serial_queries", false]], "serialize_path() (iblrig.pydantic_definitions.hardwaresettingsmicrophone method)": [[189, "iblrig.pydantic_definitions.HardwareSettingsMicrophone.serialize_path", false]], "serialsingleton (class in iblrig.serial_singleton)": [[205, "iblrig.serial_singleton.SerialSingleton", false]], "serialsingletonexception": [[206, "iblrig.serial_singleton.SerialSingletonException", false]], "services (iblrig.net.auxiliaries attribute)": [[160, "iblrig.net.Auxiliaries.services", false]], "session (class in iblrig_tasks._iblrig_tasks_advancedchoiceworld.task)": [[260, "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_biasedchoiceworld.task)": [[263, "iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_ephyschoiceworld.task)": [[266, "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_habituationchoiceworld.task)": [[269, "iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_imagingchoiceworld.task)": [[257, "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_passivechoiceworld.task)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_spontaneous.task)": [[280, "iblrig_tasks._iblrig_tasks_spontaneous.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_trainingchoiceworld.task)": [[283, "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session", false]], "session (class in iblrig_tasks._iblrig_tasks_trainingphasechoiceworld.task)": [[287, "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session", false]], "session_folder (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.session_folder", false]], "session_info (iblrig.gui.wizard.rigwizard attribute)": [[118, "iblrig.gui.wizard.RigWizard.session_info", false]], "sessioncopier (class in iblrig.transfer_experiments)": [[233, "iblrig.transfer_experiments.SessionCopier", false]], "sessionrelatedblocks (class in iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task)": [[274, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks", false]], "set_status_led() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.set_status_led", false]], "set_thresholds() (iblrig.frame2ttl.frame2ttl method)": [[49, "iblrig.frame2ttl.Frame2TTL.set_thresholds", false]], "setactive() (iblrig.gui.tools.statefulbutton method)": [[81, "iblrig.gui.tools.StatefulButton.setActive", false]], "setdata() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.setData", false]], "setdataframe() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.setDataFrame", false]], "setfontsize() (iblrig.gui.tab_log.tablog method)": [[73, "iblrig.gui.tab_log.TabLog.setFontSize", false]], "setlogcolor() (iblrig.gui.tab_log.tablog method)": [[73, "iblrig.gui.tab_log.TabLog.setLogColor", false]], "settings (iblrig.rig_component.rigcomponent property)": [[200, "iblrig.rig_component.RigComponent.settings", false]], "settings (iblrig.valve.valve property)": [[240, "iblrig.valve.Valve.settings", false]], "setup (iblrig.pydantic_definitions.hardwaresettingscameraworkflow attribute)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.setup", false]], "setupui() (iblrig.gui.ui_frame2ttl.ui_frame2ttl method)": [[86, "iblrig.gui.ui_frame2ttl.Ui_frame2ttl.setupUi", false]], "setupui() (iblrig.gui.ui_login.ui_login method)": [[88, "iblrig.gui.ui_login.Ui_login.setupUi", false]], "setupui() (iblrig.gui.ui_splash.ui_splash method)": [[90, "iblrig.gui.ui_splash.Ui_splash.setupUi", false]], "setupui() (iblrig.gui.ui_tab_about.ui_tababout method)": [[92, "iblrig.gui.ui_tab_about.Ui_TabAbout.setupUi", false]], "setupui() (iblrig.gui.ui_tab_data.ui_tabdata method)": [[94, "iblrig.gui.ui_tab_data.Ui_TabData.setupUi", false]], "setupui() (iblrig.gui.ui_tab_docs.ui_tabdocs method)": [[96, "iblrig.gui.ui_tab_docs.Ui_TabDocs.setupUi", false]], "setupui() (iblrig.gui.ui_tab_log.ui_tablog method)": [[98, "iblrig.gui.ui_tab_log.Ui_TabLog.setupUi", false]], "setupui() (iblrig.gui.ui_tab_session.ui_tabsession method)": [[100, "iblrig.gui.ui_tab_session.Ui_tabSession.setupUi", false]], "setupui() (iblrig.gui.ui_update.ui_update method)": [[102, "iblrig.gui.ui_update.Ui_update.setupUi", false]], "setupui() (iblrig.gui.ui_validation.ui_validation method)": [[104, "iblrig.gui.ui_validation.Ui_validation.setupUi", false]], "setupui() (iblrig.gui.ui_valve.ui_valve method)": [[106, "iblrig.gui.ui_valve.Ui_valve.setupUi", false]], "setupui() (iblrig.gui.ui_wizard.ui_wizard method)": [[108, "iblrig.gui.ui_wizard.Ui_wizard.setupUi", false]], "show_trial_log() (iblrig.base_choice_world.activechoiceworldsession method)": [[3, "iblrig.base_choice_world.ActiveChoiceWorldSession.show_trial_log", false]], "show_trial_log() (iblrig.base_choice_world.biasedchoiceworldsession method)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.show_trial_log", false]], "show_trial_log() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.show_trial_log", false]], "show_trial_log() (iblrig.base_choice_world.trainingchoiceworldsession method)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.show_trial_log", false]], "showevent() (iblrig.gui.tab_data.tabdata method)": [[67, "iblrig.gui.tab_data.TabData.showEvent", false]], "signals (iblrig.gui.tools.worker attribute)": [[82, "iblrig.gui.tools.Worker.signals", false]], "signed_contrast (iblrig.base_choice_world.trainingchoiceworldtrialdata attribute)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData.signed_contrast", false]], "sizeof_fmt() (in module iblrig.gui.tab_data)": [[68, "iblrig.gui.tab_data.sizeof_fmt", false]], "skip (iblrig.hardware_validation.status attribute)": [[130, "iblrig.hardware_validation.Status.SKIP", false]], "softcode (class in iblrig.hardware)": [[125, "iblrig.hardware.SOFTCODE", false]], "softcode_dictionary() (iblrig.base_tasks.bpodmixin method)": [[17, "iblrig.base_tasks.BpodMixin.softcode_dictionary", false]], "softcodes (iblrig.hardware.bpod attribute)": [[123, "iblrig.hardware.Bpod.softcodes", false]], "solution (iblrig.hardware_validation.result attribute)": [[129, "iblrig.hardware_validation.Result.solution", false]], "sort() (iblrig.gui.tools.dataframetablemodel method)": [[76, "iblrig.gui.tools.DataFrameTableModel.sort", false]], "sound_board_bpod_port (iblrig.pydantic_definitions.hardwaresettingsbpod attribute)": [[185, "iblrig.pydantic_definitions.HardwareSettingsBpod.SOUND_BOARD_BPOD_PORT", false]], "sound_card (iblrig.hardware.bpod property)": [[123, "iblrig.hardware.Bpod.sound_card", false]], "sound_device_factory() (in module iblrig.hardware)": [[127, "iblrig.hardware.sound_device_factory", false]], "sound_play_noise() (iblrig.base_tasks.soundmixin method)": [[24, "iblrig.base_tasks.SoundMixin.sound_play_noise", false]], "sound_play_tone() (iblrig.base_tasks.soundmixin method)": [[24, "iblrig.base_tasks.SoundMixin.sound_play_tone", false]], "soundmixin (class in iblrig.base_tasks)": [[24, "iblrig.base_tasks.SoundMixin", false]], "spec_version (iblrig.net.expinfo attribute)": [[161, "iblrig.net.ExpInfo.spec_version", false]], "splash (class in iblrig.gui.splash)": [[60, "iblrig.gui.splash.Splash", false]], "spontaneoussession (class in iblrig.base_tasks)": [[25, "iblrig.base_tasks.SpontaneousSession", false]], "stable (iblrig.scale.scaledata attribute)": [[203, "iblrig.scale.ScaleData.stable", false]], "start_hardware() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.start_hardware", false]], "start_hardware() (iblrig.base_tasks.basesession method)": [[14, "iblrig.base_tasks.BaseSession.start_hardware", false]], "start_hardware() (iblrig.base_tasks.emptysession method)": [[18, "iblrig.base_tasks.EmptySession.start_hardware", false]], "start_hardware() (iblrig.base_tasks.spontaneoussession method)": [[25, "iblrig.base_tasks.SpontaneousSession.start_hardware", false]], "start_hardware() (iblrig_tasks._iblrig_tasks_passivechoiceworld.task.session method)": [[277, "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session.start_hardware", false]], "start_mixin_bonsai_cameras() (iblrig.base_tasks.bonsairecordingmixin method)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin.start_mixin_bonsai_cameras", false]], "start_mixin_bonsai_microphone() (iblrig.base_tasks.bonsairecordingmixin method)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin.start_mixin_bonsai_microphone", false]], "start_mixin_bonsai_visual_stimulus() (iblrig.base_tasks.bonsaivisualstimulusmixin method)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin.start_mixin_bonsai_visual_stimulus", false]], "start_mixin_bpod() (iblrig.base_tasks.bpodmixin method)": [[17, "iblrig.base_tasks.BpodMixin.start_mixin_bpod", false]], "start_mixin_frame2ttl() (iblrig.base_tasks.frame2ttlmixin method)": [[19, "iblrig.base_tasks.Frame2TTLMixin.start_mixin_frame2ttl", false]], "start_mixin_network() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.start_mixin_network", false]], "start_mixin_rotary_encoder() (iblrig.base_tasks.rotaryencodermixin method)": [[23, "iblrig.base_tasks.RotaryEncoderMixin.start_mixin_rotary_encoder", false]], "start_mixin_sound() (iblrig.base_tasks.soundmixin method)": [[24, "iblrig.base_tasks.SoundMixin.start_mixin_sound", false]], "start_mixin_valve() (iblrig.base_tasks.valvemixin method)": [[26, "iblrig.base_tasks.ValveMixin.start_mixin_valve", false]], "start_next_calibration (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.start_next_calibration", false]], "start_stop() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.start_stop", false]], "state (iblrig.transfer_experiments.sessioncopier property)": [[233, "iblrig.transfer_experiments.SessionCopier.state", false]], "statechanged (iblrig.gui.tools.statefulbutton attribute)": [[81, "iblrig.gui.tools.StatefulButton.stateChanged", false], [81, "id6", false]], "statefulbutton (class in iblrig.gui.tools)": [[81, "iblrig.gui.tools.StatefulButton", false]], "static_vars() (in module iblrig.tools)": [[228, "iblrig.tools.static_vars", false]], "status (class in iblrig.hardware_validation)": [[130, "iblrig.hardware_validation.Status", false]], "status (iblrig.gui.validation.statusitem property)": [[110, "iblrig.gui.validation.StatusItem.status", false]], "status (iblrig.gui.validation.validatoritem property)": [[112, "iblrig.gui.validation.ValidatorItem.status", false]], "status (iblrig.hardware_validation.result attribute)": [[129, "iblrig.hardware_validation.Result.status", false]], "status_items (iblrig.gui.validation.systemvalidationdialog attribute)": [[111, "iblrig.gui.validation.SystemValidationDialog.status_items", false]], "statuschanged (iblrig.gui.tools.alyxobject attribute)": [[75, "iblrig.gui.tools.AlyxObject.statusChanged", false], [75, "id10", false]], "statusitem (class in iblrig.gui.validation)": [[110, "iblrig.gui.validation.StatusItem", false]], "stim_angle (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_angle", false]], "stim_freq (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_freq", false]], "stim_gain (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_gain", false]], "stim_phase (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_phase", false]], "stim_probability_left (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_probability_left", false]], "stim_reverse (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_reverse", false]], "stim_sigma (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.stim_sigma", false]], "stop() (iblrig.hifi.hifi method)": [[148, "iblrig.hifi.HiFi.stop", false]], "stop_and_close() (iblrig.gui.splash.splash method)": [[60, "iblrig.gui.splash.Splash.stop_and_close", false]], "stop_event (iblrig.net.auxiliaries attribute)": [[160, "iblrig.net.Auxiliaries.stop_event", false]], "stop_mixin_bonsai_recordings() (iblrig.base_tasks.bonsairecordingmixin method)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin.stop_mixin_bonsai_recordings", false]], "stop_mixin_bonsai_visual_stimulus() (iblrig.base_tasks.bonsaivisualstimulusmixin method)": [[16, "iblrig.base_tasks.BonsaiVisualStimulusMixin.stop_mixin_bonsai_visual_stimulus", false]], "stop_mixin_bpod() (iblrig.base_tasks.bpodmixin method)": [[17, "iblrig.base_tasks.BpodMixin.stop_mixin_bpod", false]], "stop_mixin_network() (iblrig.base_tasks.networksession method)": [[21, "iblrig.base_tasks.NetworkSession.stop_mixin_network", false]], "stop_sound (iblrig.hardware.softcode attribute)": [[125, "iblrig.hardware.SOFTCODE.STOP_SOUND", false]], "str_must_not_contain_space() (iblrig.pydantic_definitions.rigsettings class method)": [[195, "iblrig.pydantic_definitions.RigSettings.str_must_not_contain_space", false]], "streaming (iblrig.frame2ttl.frame2ttl property)": [[49, "iblrig.frame2ttl.Frame2TTL.streaming", false]], "subject (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.subject", false]], "sync_label (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.SYNC_LABEL", false]], "systemvalidationdialog (class in iblrig.gui.validation)": [[111, "iblrig.gui.validation.SystemValidationDialog", false]], "tababout (class in iblrig.gui.tab_about)": [[62, "iblrig.gui.tab_about.TabAbout", false]], "tabdata (class in iblrig.gui.tab_data)": [[67, "iblrig.gui.tab_data.TabData", false]], "tabdocs (class in iblrig.gui.tab_docs)": [[71, "iblrig.gui.tab_docs.TabDocs", false]], "tablog (class in iblrig.gui.tab_log)": [[73, "iblrig.gui.tab_log.TabLog", false]], "tag (iblrig.transfer_experiments.behaviorcopier attribute)": [[230, "iblrig.transfer_experiments.BehaviorCopier.tag", false]], "tag (iblrig.transfer_experiments.ephyscopier attribute)": [[232, "iblrig.transfer_experiments.EphysCopier.tag", false]], "tag (iblrig.transfer_experiments.sessioncopier attribute)": [[233, "iblrig.transfer_experiments.SessionCopier.tag", false]], "tag (iblrig.transfer_experiments.videocopier attribute)": [[234, "iblrig.transfer_experiments.VideoCopier.tag", false]], "tare() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.tare", false]], "tare() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.tare", false]], "tared (iblrig.gui.valve.valvecalibrationdialog attribute)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.tared", false]], "task_file (iblrig.gui.wizard.rigwizardmodel property)": [[119, "iblrig.gui.wizard.RigWizardModel.task_file", false]], "task_name (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.task_name", false]], "task_parameters (iblrig.gui.wizard.rigwizard attribute)": [[118, "iblrig.gui.wizard.RigWizard.task_parameters", false]], "task_settings (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.task_settings", false]], "test_subject_name (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.test_subject_name", false]], "threshold_dark (iblrig.frame2ttl.frame2ttl property)": [[49, "iblrig.frame2ttl.Frame2TTL.threshold_dark", false]], "threshold_light (iblrig.frame2ttl.frame2ttl property)": [[49, "iblrig.frame2ttl.Frame2TTL.threshold_light", false]], "time_elapsed (iblrig.base_tasks.basesession property)": [[14, "iblrig.base_tasks.BaseSession.time_elapsed", false]], "time_elapsed (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.time_elapsed", false]], "to_bytes() (iblrig.serial_singleton.serialsingleton static method)": [[205, "iblrig.serial_singleton.SerialSingleton.to_bytes", false]], "to_dict() (iblrig.net.expinfo method)": [[161, "iblrig.net.ExpInfo.to_dict", false]], "toggle_status_led() (iblrig.gui.wizard.rigwizard method)": [[118, "iblrig.gui.wizard.RigWizard.toggle_status_led", false]], "toggle_valve() (iblrig.gui.valve.valvecalibrationdialog method)": [[115, "iblrig.gui.valve.ValveCalibrationDialog.toggle_valve", false]], "toggle_valve() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.toggle_valve", false]], "training_contrasts_probabilities() (in module iblrig.choiceworld)": [[32, "iblrig.choiceworld.training_contrasts_probabilities", false]], "training_info (iblrig.gui.wizard.rigwizard attribute)": [[118, "iblrig.gui.wizard.RigWizard.training_info", false]], "training_phase (iblrig.base_choice_world.trainingchoiceworldtrialdata attribute)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData.training_phase", false]], "training_phase_from_contrast_set() (in module iblrig.choiceworld)": [[33, "iblrig.choiceworld.training_phase_from_contrast_set", false]], "trainingchoiceworldsession (class in iblrig.base_choice_world)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession", false]], "trainingchoiceworldtrialdata (class in iblrig.base_choice_world)": [[12, "iblrig.base_choice_world.TrainingChoiceWorldTrialData", false]], "transfer_data() (in module iblrig.commands)": [[38, "iblrig.commands.transfer_data", false]], "transfer_data_cli() (in module iblrig.commands)": [[39, "iblrig.commands.transfer_data_cli", false]], "transfer_ephys_data_cli() (in module iblrig.commands)": [[40, "iblrig.commands.transfer_ephys_data_cli", false]], "transfer_video_data_cli() (in module iblrig.commands)": [[41, "iblrig.commands.transfer_video_data_cli", false]], "trial_completed() (iblrig.base_choice_world.activechoiceworldsession method)": [[3, "iblrig.base_choice_world.ActiveChoiceWorldSession.trial_completed", false]], "trial_completed() (iblrig.base_choice_world.choiceworldsession method)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.trial_completed", false]], "trial_correct (iblrig.base_choice_world.activechoiceworldtrialdata attribute)": [[4, "iblrig.base_choice_world.ActiveChoiceWorldTrialData.trial_correct", false]], "trial_correct (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.trial_correct", false]], "trial_num (iblrig.base_choice_world.choiceworldtrialdata attribute)": [[8, "iblrig.base_choice_world.ChoiceWorldTrialData.trial_num", false]], "trialdatamodel (class in iblrig.pydantic_definitions)": [[196, "iblrig.pydantic_definitions.TrialDataModel", false]], "trialdatamodel (iblrig.base_choice_world.activechoiceworldsession attribute)": [[3, "iblrig.base_choice_world.ActiveChoiceWorldSession.TrialDataModel", false]], "trialdatamodel (iblrig.base_choice_world.biasedchoiceworldsession attribute)": [[5, "iblrig.base_choice_world.BiasedChoiceWorldSession.TrialDataModel", false]], "trialdatamodel (iblrig.base_choice_world.choiceworldsession attribute)": [[7, "iblrig.base_choice_world.ChoiceWorldSession.TrialDataModel", false]], "trialdatamodel (iblrig.base_choice_world.habituationchoiceworldsession attribute)": [[9, "iblrig.base_choice_world.HabituationChoiceWorldSession.TrialDataModel", false]], "trialdatamodel (iblrig.base_choice_world.trainingchoiceworldsession attribute)": [[11, "iblrig.base_choice_world.TrainingChoiceWorldSession.TrialDataModel", false]], "trialdatamodel (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.TrialDataModel", false]], "trialdatamodel (iblrig_tasks._iblrig_tasks_neuromodulatorchoiceworld.task.session attribute)": [[273, "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session.TrialDataModel", false]], "trigger_bonsai_cameras() (iblrig.base_tasks.bonsairecordingmixin method)": [[15, "iblrig.base_tasks.BonsaiRecordingMixin.trigger_bonsai_cameras", false]], "trigger_camera (iblrig.hardware.softcode attribute)": [[125, "iblrig.hardware.SOFTCODE.TRIGGER_CAMERA", false]], "truncated_exponential() (in module iblrig.misc)": [[158, "iblrig.misc.truncated_exponential", false]], "ui_frame2ttl (class in iblrig.gui.ui_frame2ttl)": [[86, "iblrig.gui.ui_frame2ttl.Ui_frame2ttl", false]], "ui_login (class in iblrig.gui.ui_login)": [[88, "iblrig.gui.ui_login.Ui_login", false]], "ui_splash (class in iblrig.gui.ui_splash)": [[90, "iblrig.gui.ui_splash.Ui_splash", false]], "ui_tababout (class in iblrig.gui.ui_tab_about)": [[92, "iblrig.gui.ui_tab_about.Ui_TabAbout", false]], "ui_tabdata (class in iblrig.gui.ui_tab_data)": [[94, "iblrig.gui.ui_tab_data.Ui_TabData", false]], "ui_tabdocs (class in iblrig.gui.ui_tab_docs)": [[96, "iblrig.gui.ui_tab_docs.Ui_TabDocs", false]], "ui_tablog (class in iblrig.gui.ui_tab_log)": [[98, "iblrig.gui.ui_tab_log.Ui_TabLog", false]], "ui_tabsession (class in iblrig.gui.ui_tab_session)": [[100, "iblrig.gui.ui_tab_session.Ui_tabSession", false]], "ui_update (class in iblrig.gui.ui_update)": [[102, "iblrig.gui.ui_update.Ui_update", false]], "ui_validation (class in iblrig.gui.ui_validation)": [[104, "iblrig.gui.ui_validation.Ui_validation", false]], "ui_valve (class in iblrig.gui.ui_valve)": [[106, "iblrig.gui.ui_valve.Ui_valve", false]], "ui_wizard (class in iblrig.gui.ui_wizard)": [[108, "iblrig.gui.ui_wizard.Ui_wizard", false]], "ul2ms() (iblrig.valve.valvevalues method)": [[241, "iblrig.valve.ValveValues.ul2ms", false]], "underline (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.UNDERLINE", false]], "unit (iblrig.scale.scaledata attribute)": [[203, "iblrig.scale.ScaleData.unit", false]], "update (iblrig.gui.tab_data.dataworker attribute)": [[66, "iblrig.gui.tab_data.DataWorker.update", false]], "update() (iblrig.gui.tools.remotedevicesitemmodel method)": [[79, "iblrig.gui.tools.RemoteDevicesItemModel.update", false]], "update() (iblrig.gui.valve.calibrationplot method)": [[114, "iblrig.gui.valve.CalibrationPlot.update", false]], "update_alyx_token() (in module iblrig.net)": [[168, "iblrig.net.update_alyx_token", false]], "update_data() (iblrig.gui.tools.diskspaceindicator method)": [[77, "iblrig.gui.tools.DiskSpaceIndicator.update_data", false]], "update_graphics() (iblrig.online_plots.onlineplots method)": [[171, "iblrig.online_plots.OnlinePlots.update_graphics", false]], "update_titles() (iblrig.online_plots.onlineplots method)": [[171, "iblrig.online_plots.OnlinePlots.update_titles", false]], "update_trial() (iblrig.online_plots.datamodel method)": [[170, "iblrig.online_plots.DataModel.update_trial", false]], "update_trial() (iblrig.online_plots.onlineplots method)": [[171, "iblrig.online_plots.OnlinePlots.update_trial", false]], "updatenotice (class in iblrig.gui.wizard)": [[120, "iblrig.gui.wizard.UpdateNotice", false]], "upgrade() (in module iblrig.upgrade_iblrig)": [[238, "iblrig.upgrade_iblrig.upgrade", false]], "url (iblrig.hardware_validation.result attribute)": [[129, "iblrig.hardware_validation.Result.url", false]], "user (iblrig.gui.wizard.rigwizardmodel attribute)": [[119, "iblrig.gui.wizard.RigWizardModel.user", false]], "username (iblrig.gui.tools.alyxobject attribute)": [[75, "iblrig.gui.tools.AlyxObject.username", false]], "username (iblrig.gui.tools.alyxobject property)": [[75, "id13", false]], "valid_path() (iblrig.pydantic_definitions.hardwaresettingscameraworkflow class method)": [[187, "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow.valid_path", false]], "validate_remote_data_path() (iblrig.pydantic_definitions.rigsettings class method)": [[195, "iblrig.pydantic_definitions.RigSettings.validate_remote_data_path", false]], "validatehardwareerror": [[131, "iblrig.hardware_validation.ValidateHardwareError", false]], "validation() (iblrig.gui.splash.splash method)": [[60, "iblrig.gui.splash.Splash.validation", false]], "validation_results (iblrig.gui.splash.splash attribute)": [[60, "iblrig.gui.splash.Splash.validation_results", false]], "validator (class in iblrig.hardware_validation)": [[132, "iblrig.hardware_validation.Validator", false]], "validator (iblrig.gui.validation.validatoritem attribute)": [[112, "iblrig.gui.validation.ValidatorItem.validator", false]], "validator (iblrig.rig_component.rigcomponent property)": [[200, "iblrig.rig_component.RigComponent.validator", false]], "validator_items (iblrig.gui.validation.systemvalidationdialog attribute)": [[111, "iblrig.gui.validation.SystemValidationDialog.validator_items", false]], "validatoralyx (class in iblrig.hardware_validation)": [[133, "iblrig.hardware_validation.ValidatorAlyx", false]], "validatorambientmodule (class in iblrig.hardware_validation)": [[134, "iblrig.hardware_validation.ValidatorAmbientModule", false]], "validatorbpod (class in iblrig.hardware_validation)": [[135, "iblrig.hardware_validation.ValidatorBpod", false]], "validatorcamera (class in iblrig.hardware_validation)": [[136, "iblrig.hardware_validation.ValidatorCamera", false]], "validatorframe2ttl (class in iblrig.hardware_validation)": [[137, "iblrig.hardware_validation.ValidatorFrame2TTL", false]], "validatorgit (class in iblrig.hardware_validation)": [[138, "iblrig.hardware_validation.ValidatorGit", false]], "validatoritem (class in iblrig.gui.validation)": [[112, "iblrig.gui.validation.ValidatorItem", false]], "validatormic (class in iblrig.hardware_validation)": [[139, "iblrig.hardware_validation.ValidatorMic", false]], "validatorrotaryencodermodule (class in iblrig.hardware_validation)": [[140, "iblrig.hardware_validation.ValidatorRotaryEncoderModule", false]], "validatorserial (class in iblrig.hardware_validation)": [[141, "iblrig.hardware_validation.ValidatorSerial", false]], "validatorsound (class in iblrig.hardware_validation)": [[142, "iblrig.hardware_validation.ValidatorSound", false]], "validatorvalve (class in iblrig.hardware_validation)": [[143, "iblrig.hardware_validation.ValidatorValve", false]], "values (iblrig.gui.valve.calibrationplot property)": [[114, "iblrig.gui.valve.CalibrationPlot.values", false]], "values() (iblrig.pydantic_definitions.bunchmodel method)": [[182, "iblrig.pydantic_definitions.BunchModel.values", false]], "valve (class in iblrig.valve)": [[240, "iblrig.valve.Valve", false]], "valve() (iblrig.hardware.bpod method)": [[123, "iblrig.hardware.Bpod.valve", false]], "valve_open() (iblrig.base_tasks.valvemixin method)": [[26, "iblrig.base_tasks.ValveMixin.valve_open", false]], "valvecalibrationdialog (class in iblrig.gui.valve)": [[115, "iblrig.gui.valve.ValveCalibrationDialog", false]], "valvemixin (class in iblrig.base_tasks)": [[26, "iblrig.base_tasks.ValveMixin", false]], "valvevalues (class in iblrig.valve)": [[241, "iblrig.valve.ValveValues", false]], "version (iblrig.base_tasks.basesession attribute)": [[14, "iblrig.base_tasks.BaseSession.version", false]], "version (iblrig.pydantic_definitions.hardwaresettings attribute)": [[184, "iblrig.pydantic_definitions.HardwareSettings.VERSION", false]], "videocopier (class in iblrig.transfer_experiments)": [[234, "iblrig.transfer_experiments.VideoCopier", false]], "view_session() (in module iblrig.commands)": [[42, "iblrig.commands.view_session", false]], "volumes_ul (iblrig.valve.valvevalues property)": [[241, "iblrig.valve.ValveValues.volumes_ul", false]], "warn (iblrig.hardware_validation.status attribute)": [[130, "iblrig.hardware_validation.Status.WARN", false]], "water_calibration_date (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.WATER_CALIBRATION_DATE", false]], "water_calibration_n (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.WATER_CALIBRATION_N", false]], "water_calibration_open_times (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.WATER_CALIBRATION_OPEN_TIMES", false]], "water_calibration_range (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.WATER_CALIBRATION_RANGE", false]], "water_calibration_weight_perdrop (iblrig.pydantic_definitions.hardwaresettingsvalve attribute)": [[194, "iblrig.pydantic_definitions.HardwareSettingsValve.WATER_CALIBRATION_WEIGHT_PERDROP", false]], "water_delivered (iblrig.online_plots.datamodel attribute)": [[170, "iblrig.online_plots.DataModel.water_delivered", false]], "weight (iblrig.scale.scaledata attribute)": [[203, "iblrig.scale.ScaleData.weight", false]], "weights_g (iblrig.valve.valvevalues property)": [[241, "iblrig.valve.ValveValues.weights_g", false]], "white (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.WHITE", false]], "width (iblrig.pydantic_definitions.hardwaresettingscamera attribute)": [[186, "iblrig.pydantic_definitions.HardwareSettingsCamera.WIDTH", false]], "worker (class in iblrig.gui.tools)": [[82, "iblrig.gui.tools.Worker", false]], "workersignals (class in iblrig.gui.tools)": [[83, "iblrig.gui.tools.WorkerSignals", false]], "write() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.write", false]], "write_packed() (iblrig.serial_singleton.serialsingleton method)": [[205, "iblrig.serial_singleton.SerialSingleton.write_packed", false]], "yellow (iblrig.tools.ansi attribute)": [[219, "iblrig.tools.ANSI.YELLOW", false]], "zero() (iblrig.scale.scale method)": [[202, "iblrig.scale.Scale.zero", false]]}, "objects": {"": [[1, 0, 0, "-", "iblrig"], [254, 0, 0, "-", "iblrig_tasks"]], "iblrig": [[2, 0, 0, "-", "base_choice_world"], [13, 0, 0, "-", "base_tasks"], [27, 0, 0, "-", "choiceworld"], [34, 0, 0, "-", "commands"], [43, 0, 0, "-", "constants"], [44, 0, 0, "-", "ephys"], [48, 0, 0, "-", "frame2ttl"], [50, 0, 0, "-", "graphic"], [52, 0, 0, "-", "gui"], [122, 0, 0, "-", "hardware"], [128, 0, 0, "-", "hardware_validation"], [147, 0, 0, "-", "hifi"], [150, 0, 0, "-", "misc"], [159, 0, 0, "-", "net"], [169, 0, 0, "-", "online_plots"], [172, 0, 0, "-", "path_helper"], [181, 0, 0, "-", "pydantic_definitions"], [197, 0, 0, "-", "raw_data_loaders"], [199, 0, 0, "-", "rig_component"], [201, 0, 0, "-", "scale"], [204, 0, 0, "-", "serial_singleton"], [210, 0, 0, "-", "session_creator"], [214, 0, 0, "-", "sound"], [218, 0, 0, "-", "tools"], [229, 0, 0, "-", "transfer_experiments"], [236, 0, 0, "-", "upgrade_iblrig"], [239, 0, 0, "-", "valve"], [242, 0, 0, "-", "version_management"]], "iblrig.base_choice_world": [[3, 1, 1, "", "ActiveChoiceWorldSession"], [4, 1, 1, "", "ActiveChoiceWorldTrialData"], [5, 1, 1, "", "BiasedChoiceWorldSession"], [6, 1, 1, "", "BiasedChoiceWorldTrialData"], [7, 1, 1, "", "ChoiceWorldSession"], [8, 1, 1, "", "ChoiceWorldTrialData"], [9, 1, 1, "", "HabituationChoiceWorldSession"], [10, 1, 1, "", "HabituationChoiceWorldTrialData"], [11, 1, 1, "", "TrainingChoiceWorldSession"], [12, 1, 1, "", "TrainingChoiceWorldTrialData"]], "iblrig.base_choice_world.ActiveChoiceWorldSession": [[3, 2, 1, "", "TrialDataModel"], [3, 3, 1, "", "__init__"], [3, 3, 1, "", "show_trial_log"], [3, 3, 1, "", "trial_completed"]], "iblrig.base_choice_world.ActiveChoiceWorldTrialData": [[4, 2, 1, "", "model_computed_fields"], [4, 2, 1, "", "model_config"], [4, 2, 1, "", "model_fields"], [4, 2, 1, "", "response_side"], [4, 2, 1, "", "response_time"], [4, 2, 1, "", "trial_correct"]], "iblrig.base_choice_world.BiasedChoiceWorldSession": [[5, 2, 1, "", "TrialDataModel"], [5, 3, 1, "", "__init__"], [5, 2, 1, "", "base_parameters_file"], [5, 3, 1, "", "new_block"], [5, 3, 1, "", "next_trial"], [5, 2, 1, "", "protocol_name"], [5, 3, 1, "", "show_trial_log"]], "iblrig.base_choice_world.BiasedChoiceWorldTrialData": [[6, 2, 1, "", "block_num"], [6, 2, 1, "", "block_trial_num"], [6, 2, 1, "", "model_computed_fields"], [6, 2, 1, "", "model_config"], [6, 2, 1, "", "model_fields"]], "iblrig.base_choice_world.ChoiceWorldSession": [[7, 2, 1, "", "TrialDataModel"], [7, 3, 1, "", "__init__"], [7, 2, 1, "", "base_parameters_file"], [7, 3, 1, "", "check_sync_pulses"], [7, 4, 1, "", "default_reward_amount"], [7, 3, 1, "", "draw_next_trial_info"], [7, 4, 1, "", "event_error"], [7, 4, 1, "", "event_reward"], [7, 3, 1, "", "extra_parser"], [7, 3, 1, "", "get_graphviz_task"], [7, 3, 1, "", "get_state_machine_trial"], [7, 4, 1, "", "iti_reward"], [7, 3, 1, "", "mock"], [7, 3, 1, "", "next_trial"], [7, 4, 1, "", "position"], [7, 4, 1, "", "quiescent_period"], [7, 4, 1, "", "reward_time"], [7, 3, 1, "", "show_trial_log"], [7, 3, 1, "", "start_hardware"], [7, 3, 1, "", "trial_completed"]], "iblrig.base_choice_world.ChoiceWorldTrialData": [[8, 2, 1, "", "contrast"], [8, 2, 1, "", "model_computed_fields"], [8, 2, 1, "", "model_config"], [8, 2, 1, "", "model_fields"], [8, 2, 1, "", "pause_duration"], [8, 2, 1, "", "position"], [8, 2, 1, "", "quiescent_period"], [8, 2, 1, "", "response_side"], [8, 2, 1, "", "response_time"], [8, 2, 1, "", "reward_amount"], [8, 2, 1, "", "reward_valve_time"], [8, 2, 1, "", "stim_angle"], [8, 2, 1, "", "stim_freq"], [8, 2, 1, "", "stim_gain"], [8, 2, 1, "", "stim_phase"], [8, 2, 1, "", "stim_probability_left"], [8, 2, 1, "", "stim_reverse"], [8, 2, 1, "", "stim_sigma"], [8, 2, 1, "", "trial_correct"], [8, 2, 1, "", "trial_num"]], "iblrig.base_choice_world.HabituationChoiceWorldSession": [[9, 2, 1, "", "TrialDataModel"], [9, 3, 1, "", "draw_next_trial_info"], [9, 3, 1, "", "get_state_machine_trial"], [9, 3, 1, "", "next_trial"], [9, 2, 1, "", "protocol_name"]], "iblrig.base_choice_world.HabituationChoiceWorldTrialData": [[10, 2, 1, "", "delay_to_stim_center"], [10, 2, 1, "", "model_computed_fields"], [10, 2, 1, "", "model_config"], [10, 2, 1, "", "model_fields"]], "iblrig.base_choice_world.TrainingChoiceWorldSession": [[11, 2, 1, "", "TrialDataModel"], [11, 3, 1, "", "__init__"], [11, 3, 1, "", "check_training_phase"], [11, 3, 1, "", "compute_performance"], [11, 4, 1, "", "default_reward_amount"], [11, 3, 1, "", "get_subject_training_info"], [11, 3, 1, "", "next_trial"], [11, 2, 1, "", "protocol_name"], [11, 3, 1, "", "show_trial_log"]], "iblrig.base_choice_world.TrainingChoiceWorldTrialData": [[12, 2, 1, "", "debias_trial"], [12, 2, 1, "", "model_computed_fields"], [12, 2, 1, "", "model_config"], [12, 2, 1, "", "model_fields"], [12, 2, 1, "", "signed_contrast"], [12, 2, 1, "", "training_phase"]], "iblrig.base_tasks": [[14, 1, 1, "", "BaseSession"], [15, 1, 1, "", "BonsaiRecordingMixin"], [16, 1, 1, "", "BonsaiVisualStimulusMixin"], [17, 1, 1, "", "BpodMixin"], [18, 1, 1, "", "EmptySession"], [19, 1, 1, "", "Frame2TTLMixin"], [20, 1, 1, "", "HasBpod"], [21, 1, 1, "", "NetworkSession"], [22, 1, 1, "", "OSCClient"], [23, 1, 1, "", "RotaryEncoderMixin"], [24, 1, 1, "", "SoundMixin"], [25, 1, 1, "", "SpontaneousSession"], [26, 1, 1, "", "ValveMixin"]], "iblrig.base_tasks.BaseSession": [[14, 2, 1, "", "TrialDataModel"], [14, 3, 1, "", "__init__"], [14, 2, 1, "", "base_parameters_file"], [14, 3, 1, "", "create_session"], [14, 4, 1, "", "exp_ref"], [14, 2, 1, "", "experiment_description"], [14, 3, 1, "", "extra_parser"], [14, 2, 1, "", "extractor_tasks"], [14, 3, 1, "", "get_task_directory"], [14, 3, 1, "", "get_task_file"], [14, 2, 1, "", "is_mock"], [14, 2, 1, "", "logger"], [14, 3, 1, "", "make_experiment_description_dict"], [14, 3, 1, "", "mock"], [14, 4, 1, "", "one"], [14, 4, 1, "", "protocol_name"], [14, 3, 1, "", "read_task_parameter_files"], [14, 3, 1, "", "register_to_alyx"], [14, 3, 1, "", "run"], [14, 3, 1, "", "save_task_parameters_to_json_file"], [14, 3, 1, "", "save_trial_data_to_json"], [14, 3, 1, "", "start_hardware"], [14, 4, 1, "", "time_elapsed"], [14, 2, 1, "", "version"]], "iblrig.base_tasks.BonsaiRecordingMixin": [[15, 2, 1, "", "config"], [15, 3, 1, "", "init_mixin_bonsai_recordings"], [15, 3, 1, "", "start_mixin_bonsai_cameras"], [15, 3, 1, "", "start_mixin_bonsai_microphone"], [15, 3, 1, "", "stop_mixin_bonsai_recordings"], [15, 3, 1, "", "trigger_bonsai_cameras"]], "iblrig.base_tasks.BonsaiVisualStimulusMixin": [[16, 3, 1, "", "choice_world_visual_stimulus"], [16, 3, 1, "", "init_mixin_bonsai_visual_stimulus"], [16, 3, 1, "", "run_passive_visual_stim"], [16, 3, 1, "", "send_trial_info_to_bonsai"], [16, 3, 1, "", "start_mixin_bonsai_visual_stimulus"], [16, 3, 1, "", "stop_mixin_bonsai_visual_stimulus"]], "iblrig.base_tasks.BpodMixin": [[17, 3, 1, "", "init_mixin_bpod"], [17, 3, 1, "", "send_spacers"], [17, 3, 1, "", "softcode_dictionary"], [17, 3, 1, "", "start_mixin_bpod"], [17, 3, 1, "", "stop_mixin_bpod"]], "iblrig.base_tasks.EmptySession": [[18, 2, 1, "", "protocol_name"], [18, 3, 1, "", "start_hardware"]], "iblrig.base_tasks.Frame2TTLMixin": [[19, 3, 1, "", "init_mixin_frame2ttl"], [19, 3, 1, "", "start_mixin_frame2ttl"]], "iblrig.base_tasks.HasBpod": [[20, 3, 1, "", "__init__"], [20, 2, 1, "", "bpod"]], "iblrig.base_tasks.NetworkSession": [[21, 3, 1, "", "__init__"], [21, 3, 1, "", "cleanup_mixin_network"], [21, 3, 1, "", "communicate"], [21, 3, 1, "", "connect"], [21, 2, 1, "", "exp_ref"], [21, 3, 1, "", "get_exp_info"], [21, 3, 1, "", "init_mixin_network"], [21, 4, 1, "", "one"], [21, 2, 1, "", "remote_rigs"], [21, 3, 1, "", "run"], [21, 3, 1, "", "start_mixin_network"], [21, 3, 1, "", "stop_mixin_network"]], "iblrig.base_tasks.OSCClient": [[22, 2, 1, "", "OSC_PROTOCOL"], [22, 3, 1, "", "__init__"], [22, 3, 1, "", "exit"], [22, 3, 1, "", "send2bonsai"]], "iblrig.base_tasks.RotaryEncoderMixin": [[23, 3, 1, "", "init_mixin_rotary_encoder"], [23, 3, 1, "", "start_mixin_rotary_encoder"]], "iblrig.base_tasks.SoundMixin": [[24, 3, 1, "", "init_mixin_sound"], [24, 3, 1, "", "sound_play_noise"], [24, 3, 1, "", "sound_play_tone"], [24, 3, 1, "", "start_mixin_sound"]], "iblrig.base_tasks.SpontaneousSession": [[25, 3, 1, "", "__init__"], [25, 3, 1, "", "start_hardware"]], "iblrig.base_tasks.ValveMixin": [[26, 3, 1, "", "compute_reward_time"], [26, 3, 1, "", "init_mixin_valve"], [26, 3, 1, "", "start_mixin_valve"], [26, 3, 1, "", "valve_open"]], "iblrig.choiceworld": [[28, 5, 1, "", "compute_adaptive_reward_volume"], [29, 5, 1, "", "contrasts_set"], [30, 5, 1, "", "draw_training_contrast"], [31, 5, 1, "", "get_subject_training_info"], [32, 5, 1, "", "training_contrasts_probabilities"], [33, 5, 1, "", "training_phase_from_contrast_set"]], "iblrig.commands": [[35, 5, 1, "", "dir_path"], [36, 5, 1, "", "flush"], [37, 5, 1, "", "remove_local_sessions"], [38, 5, 1, "", "transfer_data"], [39, 5, 1, "", "transfer_data_cli"], [40, 5, 1, "", "transfer_ephys_data_cli"], [41, 5, 1, "", "transfer_video_data_cli"], [42, 5, 1, "", "view_session"]], "iblrig.ephys": [[45, 5, 1, "", "neuropixel24_micromanipulator_coordinates"], [46, 5, 1, "", "prepare_ephys_session"], [47, 5, 1, "", "prepare_ephys_session_cmd"]], "iblrig.frame2ttl": [[49, 1, 1, "", "Frame2TTL"]], "iblrig.frame2ttl.Frame2TTL": [[49, 3, 1, "", "__init__"], [49, 3, 1, "", "calibrate"], [49, 3, 1, "", "handshake"], [49, 3, 1, "", "sample"], [49, 3, 1, "", "set_thresholds"], [49, 4, 1, "", "streaming"], [49, 4, 1, "", "threshold_dark"], [49, 4, 1, "", "threshold_light"]], "iblrig.graphic": [[51, 5, 1, "", "numinput"]], "iblrig.gui": [[53, 0, 0, "-", "frame2ttl"], [56, 0, 0, "-", "resources_rc"], [59, 0, 0, "-", "splash"], [61, 0, 0, "-", "tab_about"], [63, 0, 0, "-", "tab_data"], [69, 0, 0, "-", "tab_docs"], [72, 0, 0, "-", "tab_log"], [74, 0, 0, "-", "tools"], [85, 0, 0, "-", "ui_frame2ttl"], [87, 0, 0, "-", "ui_login"], [89, 0, 0, "-", "ui_splash"], [91, 0, 0, "-", "ui_tab_about"], [93, 0, 0, "-", "ui_tab_data"], [95, 0, 0, "-", "ui_tab_docs"], [97, 0, 0, "-", "ui_tab_log"], [99, 0, 0, "-", "ui_tab_session"], [101, 0, 0, "-", "ui_update"], [103, 0, 0, "-", "ui_validation"], [105, 0, 0, "-", "ui_valve"], [107, 0, 0, "-", "ui_wizard"], [109, 0, 0, "-", "validation"], [113, 0, 0, "-", "valve"], [116, 0, 0, "-", "wizard"]], "iblrig.gui.frame2ttl": [[54, 1, 1, "", "Frame2TTLCalibrationDialog"], [55, 1, 1, "", "Frame2TTLCalibrationTarget"]], "iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog": [[54, 3, 1, "", "__init__"]], "iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget": [[55, 3, 1, "", "__init__"], [55, 4, 1, "", "color"]], "iblrig.gui.resources_rc": [[57, 5, 1, "", "qCleanupResources"], [58, 5, 1, "", "qInitResources"]], "iblrig.gui.splash": [[60, 1, 1, "", "Splash"]], "iblrig.gui.splash.Splash": [[60, 3, 1, "", "__init__"], [60, 3, 1, "", "close"], [60, 3, 1, "", "eventFilter"], [60, 3, 1, "", "stop_and_close"], [60, 3, 1, "", "validation"], [60, 2, 1, "", "validation_results"]], "iblrig.gui.tab_about": [[62, 1, 1, "", "TabAbout"]], "iblrig.gui.tab_about.TabAbout": [[62, 3, 1, "", "__init__"], [62, 3, 1, "", "onGetAnydeskResult"]], "iblrig.gui.tab_data": [[64, 1, 1, "", "Column"], [65, 1, 1, "", "DataItemDelegate"], [66, 1, 1, "", "DataWorker"], [67, 1, 1, "", "TabData"], [68, 5, 1, "", "sizeof_fmt"]], "iblrig.gui.tab_data.Column": [[64, 3, 1, "", "__new__"], [64, 2, 1, "", "hidden"], [64, 2, 1, "", "name"], [64, 2, 1, "", "resizeMode"], [64, 2, 1, "", "sectionWidth"]], "iblrig.gui.tab_data.DataItemDelegate": [[65, 3, 1, "", "initStyleOption"]], "iblrig.gui.tab_data.DataWorker": [[66, 3, 1, "", "__init__"], [66, 2, 1, "", "initialized"], [66, 2, 1, "", "lazyLoadComplete"], [66, 3, 1, "", "lazyLoadStatus"], [66, 3, 1, "", "run"], [66, 2, 1, "", "update"]], "iblrig.gui.tab_data.TabData": [[67, 3, 1, "", "__init__"], [67, 3, 1, "", "showEvent"]], "iblrig.gui.tab_docs": [[70, 1, 1, "", "CustomWebEnginePage"], [71, 1, 1, "", "TabDocs"]], "iblrig.gui.tab_docs.CustomWebEnginePage": [[70, 3, 1, "", "acceptNavigationRequest"]], "iblrig.gui.tab_docs.TabDocs": [[71, 3, 1, "", "__init__"]], "iblrig.gui.tab_log": [[73, 1, 1, "", "TabLog"]], "iblrig.gui.tab_log.TabLog": [[73, 3, 1, "", "__init__"], [73, 3, 1, "", "appendText"], [73, 3, 1, "", "clear"], [73, 3, 1, "", "copyToClipboard"], [73, 3, 1, "", "setFontSize"], [73, 3, 1, "", "setLogColor"]], "iblrig.gui.tools": [[75, 1, 1, "", "AlyxObject"], [76, 1, 1, "", "DataFrameTableModel"], [77, 1, 1, "", "DiskSpaceIndicator"], [78, 1, 1, "", "LineEditAlyxUser"], [79, 1, 1, "", "RemoteDevicesItemModel"], [80, 1, 1, "", "RemoteDevicesListView"], [81, 1, 1, "", "StatefulButton"], [82, 1, 1, "", "Worker"], [83, 1, 1, "", "WorkerSignals"], [84, 5, 1, "", "convert_uis"]], "iblrig.gui.tools.AlyxObject": [[75, 3, 1, "", "__init__"], [75, 4, 1, "id0", "isLoggedIn"], [75, 3, 1, "", "logIn"], [75, 3, 1, "", "logOut"], [75, 2, 1, "id1", "loggedIn"], [75, 2, 1, "id4", "loggedOut"], [75, 2, 1, "id7", "loginFailed"], [75, 2, 1, "id10", "statusChanged"], [75, 4, 1, "id13", "username"]], "iblrig.gui.tools.DataFrameTableModel": [[76, 3, 1, "", "__init__"], [76, 3, 1, "", "columnCount"], [76, 3, 1, "", "data"], [76, 2, 1, "", "dataFrame"], [76, 3, 1, "", "headerData"], [76, 3, 1, "", "rowCount"], [76, 3, 1, "", "setData"], [76, 3, 1, "", "setDataFrame"], [76, 3, 1, "", "sort"]], "iblrig.gui.tools.DiskSpaceIndicator": [[77, 3, 1, "", "__init__"], [77, 4, 1, "", "critical"], [77, 3, 1, "", "update_data"]], "iblrig.gui.tools.LineEditAlyxUser": [[78, 3, 1, "", "__init__"], [78, 3, 1, "", "logIn"]], "iblrig.gui.tools.RemoteDevicesItemModel": [[79, 3, 1, "", "__init__"], [79, 3, 1, "", "update"]], "iblrig.gui.tools.RemoteDevicesListView": [[80, 3, 1, "", "__init__"], [80, 3, 1, "", "getDevices"]], "iblrig.gui.tools.StatefulButton": [[81, 3, 1, "", "__init__"], [81, 2, 1, "id0", "clickedWhileActive"], [81, 2, 1, "id3", "clickedWhileInactive"], [81, 2, 1, "", "isActive"], [81, 3, 1, "", "setActive"], [81, 2, 1, "id6", "stateChanged"]], "iblrig.gui.tools.Worker": [[82, 3, 1, "", "__init__"], [82, 2, 1, "", "args"], [82, 2, 1, "", "fn"], [82, 2, 1, "", "kwargs"], [82, 3, 1, "id0", "run"], [82, 2, 1, "", "signals"]], "iblrig.gui.tools.WorkerSignals": [[83, 2, 1, "id0", "error"], [83, 2, 1, "id3", "finished"], [83, 2, 1, "id6", "progress"], [83, 2, 1, "id9", "result"]], "iblrig.gui.ui_frame2ttl": [[86, 1, 1, "", "Ui_frame2ttl"]], "iblrig.gui.ui_frame2ttl.Ui_frame2ttl": [[86, 3, 1, "", "retranslateUi"], [86, 3, 1, "", "setupUi"]], "iblrig.gui.ui_login": [[88, 1, 1, "", "Ui_login"]], "iblrig.gui.ui_login.Ui_login": [[88, 3, 1, "", "retranslateUi"], [88, 3, 1, "", "setupUi"]], "iblrig.gui.ui_splash": [[90, 1, 1, "", "Ui_splash"]], "iblrig.gui.ui_splash.Ui_splash": [[90, 3, 1, "", "retranslateUi"], [90, 3, 1, "", "setupUi"]], "iblrig.gui.ui_tab_about": [[92, 1, 1, "", "Ui_TabAbout"]], "iblrig.gui.ui_tab_about.Ui_TabAbout": [[92, 3, 1, "", "retranslateUi"], [92, 3, 1, "", "setupUi"]], "iblrig.gui.ui_tab_data": [[94, 1, 1, "", "Ui_TabData"]], "iblrig.gui.ui_tab_data.Ui_TabData": [[94, 3, 1, "", "retranslateUi"], [94, 3, 1, "", "setupUi"]], "iblrig.gui.ui_tab_docs": [[96, 1, 1, "", "Ui_TabDocs"]], "iblrig.gui.ui_tab_docs.Ui_TabDocs": [[96, 3, 1, "", "retranslateUi"], [96, 3, 1, "", "setupUi"]], "iblrig.gui.ui_tab_log": [[98, 1, 1, "", "Ui_TabLog"]], "iblrig.gui.ui_tab_log.Ui_TabLog": [[98, 3, 1, "", "retranslateUi"], [98, 3, 1, "", "setupUi"]], "iblrig.gui.ui_tab_session": [[100, 1, 1, "", "Ui_tabSession"]], "iblrig.gui.ui_tab_session.Ui_tabSession": [[100, 3, 1, "", "retranslateUi"], [100, 3, 1, "", "setupUi"]], "iblrig.gui.ui_update": [[102, 1, 1, "", "Ui_update"]], "iblrig.gui.ui_update.Ui_update": [[102, 3, 1, "", "retranslateUi"], [102, 3, 1, "", "setupUi"]], "iblrig.gui.ui_validation": [[104, 1, 1, "", "Ui_validation"]], "iblrig.gui.ui_validation.Ui_validation": [[104, 3, 1, "", "retranslateUi"], [104, 3, 1, "", "setupUi"]], "iblrig.gui.ui_valve": [[106, 1, 1, "", "Ui_valve"]], "iblrig.gui.ui_valve.Ui_valve": [[106, 3, 1, "", "retranslateUi"], [106, 3, 1, "", "setupUi"]], "iblrig.gui.ui_wizard": [[108, 1, 1, "", "Ui_wizard"]], "iblrig.gui.ui_wizard.Ui_wizard": [[108, 3, 1, "", "retranslateUi"], [108, 3, 1, "", "setupUi"]], "iblrig.gui.validation": [[110, 1, 1, "", "StatusItem"], [111, 1, 1, "", "SystemValidationDialog"], [112, 1, 1, "", "ValidatorItem"]], "iblrig.gui.validation.StatusItem": [[110, 3, 1, "", "__init__"], [110, 4, 1, "", "status"]], "iblrig.gui.validation.SystemValidationDialog": [[111, 3, 1, "", "__init__"], [111, 2, 1, "", "item_finished"], [111, 2, 1, "", "item_result"], [111, 2, 1, "", "item_started"], [111, 3, 1, "", "on_item_finished"], [111, 3, 1, "", "on_item_result"], [111, 3, 1, "", "on_item_started"], [111, 3, 1, "", "run"], [111, 3, 1, "", "run_subprocess"], [111, 2, 1, "", "status_items"], [111, 2, 1, "", "validator_items"]], "iblrig.gui.validation.ValidatorItem": [[112, 3, 1, "", "__init__"], [112, 3, 1, "", "clear"], [112, 4, 1, "", "status"], [112, 2, 1, "", "validator"]], "iblrig.gui.valve": [[114, 1, 1, "", "CalibrationPlot"], [115, 1, 1, "", "ValveCalibrationDialog"]], "iblrig.gui.valve.CalibrationPlot": [[114, 3, 1, "", "__init__"], [114, 3, 1, "", "clear"], [114, 3, 1, "", "update"], [114, 4, 1, "", "values"]], "iblrig.gui.valve.ValveCalibrationDialog": [[115, 3, 1, "", "__init__"], [115, 3, 1, "", "calibrate"], [115, 2, 1, "", "calibration_finished"], [115, 3, 1, "", "clear_calibration"], [115, 3, 1, "", "clear_crop_callback"], [115, 3, 1, "", "clear_drop"], [115, 3, 1, "", "closeEvent"], [115, 3, 1, "", "define_and_start_state_machine"], [115, 3, 1, "", "display_scale_stable"], [115, 3, 1, "", "display_scale_text"], [115, 2, 1, "", "drop_cleared"], [115, 3, 1, "", "get_next_calibration_time"], [115, 3, 1, "", "get_scale_reading"], [115, 3, 1, "", "initialize_scale"], [115, 3, 1, "", "pulse_valve"], [115, 3, 1, "", "save"], [115, 2, 1, "", "scale"], [115, 2, 1, "", "scale_initialized"], [115, 2, 1, "", "scale_stable_changed"], [115, 2, 1, "", "scale_text_changed"], [115, 2, 1, "", "start_next_calibration"], [115, 3, 1, "", "tare"], [115, 2, 1, "", "tared"], [115, 3, 1, "", "toggle_valve"]], "iblrig.gui.wizard": [[117, 1, 1, "", "LoginWindow"], [118, 1, 1, "", "RigWizard"], [119, 1, 1, "", "RigWizardModel"], [120, 1, 1, "", "UpdateNotice"], [121, 5, 1, "", "main"]], "iblrig.gui.wizard.LoginWindow": [[117, 3, 1, "", "__init__"]], "iblrig.gui.wizard.RigWizard": [[118, 3, 1, "", "__init__"], [118, 2, 1, "", "append_session"], [118, 3, 1, "", "closeEvent"], [118, 3, 1, "", "controller2model"], [118, 3, 1, "", "eventFilter"], [118, 3, 1, "", "flush"], [118, 4, 1, "", "hardware_settings"], [118, 4, 1, "", "iblrig_settings"], [118, 3, 1, "", "model2view"], [118, 2, 1, "", "new_subject_details"], [118, 3, 1, "", "pause"], [118, 2, 1, "", "previous_subject"], [118, 2, 1, "", "session_info"], [118, 3, 1, "", "start_stop"], [118, 2, 1, "", "task_parameters"], [118, 3, 1, "", "toggle_status_led"], [118, 2, 1, "", "training_info"]], "iblrig.gui.wizard.RigWizardModel": [[119, 3, 1, "", "__init__"], [119, 2, 1, "", "alyx"], [119, 2, 1, "", "file_hardware_settings"], [119, 2, 1, "", "file_iblrig_settings"], [119, 3, 1, "", "free_reward"], [119, 2, 1, "", "free_reward_time"], [119, 3, 1, "", "get_session"], [119, 3, 1, "", "get_task_extra_parser"], [119, 3, 1, "", "get_task_parameters"], [119, 3, 1, "", "login"], [119, 3, 1, "", "logout"], [119, 2, 1, "", "procedures"], [119, 2, 1, "", "projects"], [119, 2, 1, "", "session_folder"], [119, 2, 1, "", "subject"], [119, 4, 1, "", "task_file"], [119, 2, 1, "", "task_name"], [119, 2, 1, "", "test_subject_name"], [119, 2, 1, "", "user"]], "iblrig.gui.wizard.UpdateNotice": [[120, 3, 1, "", "__init__"]], "iblrig.hardware": [[123, 1, 1, "", "Bpod"], [124, 1, 1, "", "MyRotaryEncoder"], [125, 1, 1, "", "SOFTCODE"], [126, 5, 1, "", "restart_com_port"], [127, 5, 1, "", "sound_device_factory"]], "iblrig.hardware.Bpod": [[123, 3, 1, "", "__init__"], [123, 3, 1, "", "__new__"], [123, 4, 1, "", "ambient_module"], [123, 2, 1, "", "can_control_led"], [123, 3, 1, "", "close"], [123, 3, 1, "", "define_harp_sounds_actions"], [123, 3, 1, "", "define_rotary_encoder_actions"], [123, 3, 1, "", "define_xonar_sounds_actions"], [123, 3, 1, "", "flush"], [123, 3, 1, "", "get_ambient_sensor_reading"], [123, 3, 1, "", "get_module"], [123, 4, 1, "", "is_connected"], [123, 3, 1, "", "open_valve"], [123, 3, 1, "", "pulse_valve"], [123, 3, 1, "", "pulse_valve_repeatedly"], [123, 3, 1, "", "register_softcodes"], [123, 4, 1, "", "rotary_encoder"], [123, 3, 1, "", "set_status_led"], [123, 2, 1, "", "softcodes"], [123, 4, 1, "", "sound_card"], [123, 3, 1, "", "toggle_valve"], [123, 3, 1, "", "valve"]], "iblrig.hardware.MyRotaryEncoder": [[124, 3, 1, "", "__init__"], [124, 3, 1, "", "connect"]], "iblrig.hardware.SOFTCODE": [[125, 2, 1, "", "PLAY_NOISE"], [125, 2, 1, "", "PLAY_TONE"], [125, 2, 1, "", "STOP_SOUND"], [125, 2, 1, "", "TRIGGER_CAMERA"], [125, 3, 1, "", "__new__"]], "iblrig.hardware_validation": [[129, 1, 1, "", "Result"], [130, 1, 1, "", "Status"], [131, 6, 1, "", "ValidateHardwareError"], [132, 1, 1, "", "Validator"], [133, 1, 1, "", "ValidatorAlyx"], [134, 1, 1, "", "ValidatorAmbientModule"], [135, 1, 1, "", "ValidatorBpod"], [136, 1, 1, "", "ValidatorCamera"], [137, 1, 1, "", "ValidatorFrame2TTL"], [138, 1, 1, "", "ValidatorGit"], [139, 1, 1, "", "ValidatorMic"], [140, 1, 1, "", "ValidatorRotaryEncoderModule"], [141, 1, 1, "", "ValidatorSerial"], [142, 1, 1, "", "ValidatorSound"], [143, 1, 1, "", "ValidatorValve"], [144, 5, 1, "", "get_all_validators"], [145, 5, 1, "", "run_all_validators"], [146, 5, 1, "", "run_all_validators_cli"]], "iblrig.hardware_validation.Result": [[129, 3, 1, "", "__init__"], [129, 2, 1, "", "exception"], [129, 2, 1, "", "ext_message"], [129, 2, 1, "", "message"], [129, 2, 1, "", "solution"], [129, 2, 1, "", "status"], [129, 2, 1, "", "url"]], "iblrig.hardware_validation.Status": [[130, 2, 1, "", "FAIL"], [130, 2, 1, "", "INFO"], [130, 2, 1, "", "PASS"], [130, 2, 1, "", "PEND"], [130, 2, 1, "", "SKIP"], [130, 2, 1, "", "WARN"], [130, 3, 1, "", "__new__"]], "iblrig.hardware_validation.ValidateHardwareError": [[131, 3, 1, "", "__new__"]], "iblrig.hardware_validation.Validator": [[132, 3, 1, "", "__init__"], [132, 2, 1, "", "hardware_settings"], [132, 2, 1, "", "iblrig_settings"], [132, 2, 1, "", "interactive"], [132, 2, 1, "", "log_results"], [132, 4, 1, "", "name"], [132, 3, 1, "", "process"], [132, 2, 1, "", "raise_fail_as_exception"], [132, 3, 1, "", "run"]], "iblrig.hardware_validation.ValidatorBpod": [[135, 4, 1, "", "port"], [135, 2, 1, "", "port_properties"], [135, 2, 1, "", "serial_queries"]], "iblrig.hardware_validation.ValidatorFrame2TTL": [[137, 4, 1, "", "port"], [137, 2, 1, "", "serial_queries"]], "iblrig.hardware_validation.ValidatorRotaryEncoderModule": [[140, 4, 1, "", "port"], [140, 2, 1, "", "port_properties"], [140, 2, 1, "", "serial_queries"]], "iblrig.hardware_validation.ValidatorSerial": [[141, 3, 1, "", "__init__"], [141, 4, 1, "", "port"], [141, 4, 1, "", "port_info"], [141, 2, 1, "", "port_properties"], [141, 2, 1, "", "serial_queries"]], "iblrig.hardware_validation.ValidatorSound": [[142, 3, 1, "", "__init__"], [142, 4, 1, "", "port"]], "iblrig.hifi": [[148, 1, 1, "", "HiFi"], [149, 6, 1, "", "HiFiException"]], "iblrig.hifi.HiFi": [[148, 3, 1, "", "__init__"], [148, 4, 1, "", "attenuation_db"], [148, 4, 1, "", "bit_depth"], [148, 3, 1, "", "handshake"], [148, 4, 1, "", "is_hd"], [148, 3, 1, "", "load"], [148, 4, 1, "", "max_envelope_samples"], [148, 4, 1, "", "max_samples_per_waveform"], [148, 3, 1, "", "play"], [148, 3, 1, "", "push"], [148, 4, 1, "", "sampling_rate_hz"], [148, 3, 1, "", "stop"]], "iblrig.hifi.HiFiException": [[149, 3, 1, "", "__init__"], [149, 3, 1, "", "__new__"]], "iblrig.misc": [[151, 5, 1, "", "draw_contrast"], [152, 5, 1, "", "get_biased_probs"], [153, 5, 1, "", "get_port_events"], [154, 5, 1, "", "get_session_path"], [155, 5, 1, "", "get_task_argument_parser"], [156, 5, 1, "", "get_task_arguments"], [157, 5, 1, "", "online_std"], [158, 5, 1, "", "truncated_exponential"]], "iblrig.net": [[160, 1, 1, "", "Auxiliaries"], [161, 1, 1, "", "ExpInfo"], [162, 5, 1, "", "check_uri_match"], [163, 5, 1, "", "get_remote_devices"], [164, 5, 1, "", "get_remote_devices_file"], [165, 5, 1, "", "get_server_communicator"], [166, 5, 1, "", "install_alyx_token"], [167, 5, 1, "", "read_stdin"], [168, 5, 1, "", "update_alyx_token"]], "iblrig.net.Auxiliaries": [[160, 3, 1, "", "__init__"], [160, 3, 1, "", "__new__"], [160, 3, 1, "", "cleanup"], [160, 3, 1, "", "clear_message_queue"], [160, 3, 1, "", "close"], [160, 2, 1, "", "connected"], [160, 3, 1, "", "create"], [160, 4, 1, "", "is_connected"], [160, 4, 1, "", "is_running"], [160, 3, 1, "", "listen"], [160, 3, 1, "", "push"], [160, 2, 1, "", "refresh_rate"], [160, 2, 1, "", "response_received"], [160, 2, 1, "", "services"], [160, 2, 1, "", "stop_event"]], "iblrig.net.ExpInfo": [[161, 3, 1, "", "__init__"], [161, 2, 1, "", "exp_ref"], [161, 2, 1, "", "experiment_description"], [161, 2, 1, "", "main_sync"], [161, 2, 1, "", "master"], [161, 2, 1, "", "rig_version"], [161, 2, 1, "", "spec_version"], [161, 3, 1, "", "to_dict"]], "iblrig.online_plots": [[170, 1, 1, "", "DataModel"], [171, 1, 1, "", "OnlinePlots"]], "iblrig.online_plots.DataModel": [[170, 3, 1, "", "__init__"], [170, 3, 1, "", "compute_end_session_criteria"], [170, 2, 1, "", "contrast_set"], [170, 2, 1, "", "ntrials"], [170, 2, 1, "", "ntrials_correct"], [170, 2, 1, "", "ntrials_engaged"], [170, 2, 1, "", "ntrials_nan"], [170, 2, 1, "", "percent_correct"], [170, 2, 1, "", "percent_error"], [170, 2, 1, "", "probability_set"], [170, 2, 1, "", "task_settings"], [170, 2, 1, "", "time_elapsed"], [170, 3, 1, "", "update_trial"], [170, 2, 1, "", "water_delivered"]], "iblrig.online_plots.OnlinePlots": [[171, 3, 1, "", "__init__"], [171, 3, 1, "", "display_full_jsonable"], [171, 3, 1, "", "run"], [171, 3, 1, "", "update_graphics"], [171, 3, 1, "", "update_titles"], [171, 3, 1, "", "update_trial"]], "iblrig.path_helper": [[173, 5, 1, "", "create_bonsai_layout_from_template"], [174, 5, 1, "", "get_commit_hash"], [175, 5, 1, "", "get_local_and_remote_paths"], [176, 5, 1, "", "iterate_collection"], [177, 5, 1, "", "iterate_previous_sessions"], [178, 5, 1, "", "load_pydantic_yaml"], [179, 5, 1, "", "patch_settings"], [180, 5, 1, "", "save_pydantic_yaml"]], "iblrig.pydantic_definitions": [[182, 1, 1, "", "BunchModel"], [183, 7, 1, "", "ExistingFilePath"], [184, 1, 1, "", "HardwareSettings"], [185, 1, 1, "", "HardwareSettingsBpod"], [186, 1, 1, "", "HardwareSettingsCamera"], [187, 1, 1, "", "HardwareSettingsCameraWorkflow"], [188, 1, 1, "", "HardwareSettingsFrame2TTL"], [189, 1, 1, "", "HardwareSettingsMicrophone"], [190, 1, 1, "", "HardwareSettingsRotaryEncoder"], [191, 1, 1, "", "HardwareSettingsScale"], [192, 1, 1, "", "HardwareSettingsScreen"], [193, 1, 1, "", "HardwareSettingsSound"], [194, 1, 1, "", "HardwareSettingsValve"], [195, 1, 1, "", "RigSettings"], [196, 1, 1, "", "TrialDataModel"]], "iblrig.pydantic_definitions.BunchModel": [[182, 3, 1, "", "items"], [182, 3, 1, "", "keys"], [182, 2, 1, "", "model_computed_fields"], [182, 2, 1, "", "model_config"], [182, 2, 1, "", "model_fields"], [182, 3, 1, "", "values"]], "iblrig.pydantic_definitions.HardwareSettings": [[184, 2, 1, "", "MAIN_SYNC"], [184, 2, 1, "", "RIG_NAME"], [184, 2, 1, "", "VERSION"], [184, 2, 1, "", "device_bpod"], [184, 2, 1, "", "device_cameras"], [184, 2, 1, "", "device_frame2ttl"], [184, 2, 1, "", "device_microphone"], [184, 2, 1, "", "device_rotary_encoder"], [184, 2, 1, "", "device_scale"], [184, 2, 1, "", "device_screen"], [184, 2, 1, "", "device_sound"], [184, 2, 1, "", "device_valve"], [184, 2, 1, "", "model_computed_fields"], [184, 2, 1, "", "model_config"], [184, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsBpod": [[185, 2, 1, "", "BPOD_TTL_TEST_DATE"], [185, 2, 1, "", "BPOD_TTL_TEST_STATUS"], [185, 2, 1, "", "COM_BPOD"], [185, 2, 1, "", "DISABLE_BEHAVIOR_INPUT_PORTS"], [185, 2, 1, "", "ROTARY_ENCODER_BPOD_PORT"], [185, 2, 1, "", "SOUND_BOARD_BPOD_PORT"], [185, 2, 1, "", "model_computed_fields"], [185, 2, 1, "", "model_config"], [185, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsCamera": [[186, 2, 1, "", "FPS"], [186, 2, 1, "", "HEIGHT"], [186, 2, 1, "", "INDEX"], [186, 2, 1, "", "SYNC_LABEL"], [186, 2, 1, "", "WIDTH"], [186, 2, 1, "", "model_computed_fields"], [186, 2, 1, "", "model_config"], [186, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow": [[187, 2, 1, "", "model_computed_fields"], [187, 2, 1, "", "model_config"], [187, 2, 1, "", "model_fields"], [187, 2, 1, "", "recording"], [187, 2, 1, "", "setup"], [187, 3, 1, "", "valid_path"]], "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL": [[188, 2, 1, "", "COM_F2TTL"], [188, 2, 1, "", "F2TTL_CALIBRATION_DATE"], [188, 2, 1, "", "F2TTL_DARK_THRESH"], [188, 2, 1, "", "F2TTL_LIGHT_THRESH"], [188, 2, 1, "", "model_computed_fields"], [188, 2, 1, "", "model_config"], [188, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsMicrophone": [[189, 2, 1, "", "BONSAI_WORKFLOW"], [189, 2, 1, "", "model_computed_fields"], [189, 2, 1, "", "model_config"], [189, 2, 1, "", "model_fields"], [189, 3, 1, "", "serialize_path"]], "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder": [[190, 2, 1, "", "COM_ROTARY_ENCODER"], [190, 2, 1, "", "model_computed_fields"], [190, 2, 1, "", "model_config"], [190, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsScale": [[191, 2, 1, "", "COM_SCALE"], [191, 2, 1, "", "model_computed_fields"], [191, 2, 1, "", "model_config"], [191, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsScreen": [[192, 2, 1, "", "DISPLAY_IDX"], [192, 2, 1, "", "SCREEN_FREQ_TARGET"], [192, 2, 1, "", "SCREEN_FREQ_TEST_DATE"], [192, 2, 1, "", "SCREEN_FREQ_TEST_STATUS"], [192, 2, 1, "", "SCREEN_LUX_DATE"], [192, 2, 1, "", "SCREEN_LUX_VALUE"], [192, 2, 1, "", "model_computed_fields"], [192, 2, 1, "", "model_config"], [192, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsSound": [[193, 2, 1, "", "AMP_TYPE"], [193, 2, 1, "", "COM_SOUND"], [193, 2, 1, "", "OUTPUT"], [193, 2, 1, "", "model_computed_fields"], [193, 2, 1, "", "model_config"], [193, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.HardwareSettingsValve": [[194, 2, 1, "", "FREE_REWARD_VOLUME_UL"], [194, 2, 1, "", "WATER_CALIBRATION_DATE"], [194, 2, 1, "", "WATER_CALIBRATION_N"], [194, 2, 1, "", "WATER_CALIBRATION_OPEN_TIMES"], [194, 2, 1, "", "WATER_CALIBRATION_RANGE"], [194, 2, 1, "", "WATER_CALIBRATION_WEIGHT_PERDROP"], [194, 2, 1, "", "model_computed_fields"], [194, 2, 1, "", "model_config"], [194, 2, 1, "", "model_fields"]], "iblrig.pydantic_definitions.RigSettings": [[195, 2, 1, "", "ALYX_LAB"], [195, 2, 1, "", "ALYX_URL"], [195, 2, 1, "", "ALYX_USER"], [195, 2, 1, "", "iblrig_local_data_path"], [195, 2, 1, "", "iblrig_local_subjects_path"], [195, 2, 1, "", "iblrig_remote_data_path"], [195, 2, 1, "", "iblrig_remote_subjects_path"], [195, 2, 1, "", "model_computed_fields"], [195, 2, 1, "", "model_config"], [195, 2, 1, "", "model_fields"], [195, 3, 1, "", "str_must_not_contain_space"], [195, 3, 1, "", "validate_remote_data_path"]], "iblrig.pydantic_definitions.TrialDataModel": [[196, 2, 1, "", "model_computed_fields"], [196, 2, 1, "", "model_config"], [196, 2, 1, "", "model_fields"], [196, 3, 1, "", "preallocate_dataframe"]], "iblrig.raw_data_loaders": [[198, 5, 1, "", "load_task_jsonable"]], "iblrig.rig_component": [[200, 1, 1, "", "RigComponent"]], "iblrig.rig_component.RigComponent": [[200, 4, 1, "", "pretty_name"], [200, 4, 1, "", "settings"], [200, 4, 1, "", "validator"]], "iblrig.scale": [[202, 1, 1, "", "Scale"], [203, 1, 1, "", "ScaleData"]], "iblrig.scale.Scale": [[202, 3, 1, "", "__init__"], [202, 3, 1, "", "assert_setting"], [202, 3, 1, "", "get_grams"], [202, 3, 1, "", "get_stable_grams"], [202, 4, 1, "", "grams"], [202, 3, 1, "", "query_line"], [202, 3, 1, "", "tare"], [202, 3, 1, "", "zero"]], "iblrig.scale.ScaleData": [[203, 3, 1, "", "__init__"], [203, 2, 1, "", "mode"], [203, 2, 1, "", "stable"], [203, 2, 1, "", "unit"], [203, 2, 1, "", "weight"]], "iblrig.serial_singleton": [[205, 1, 1, "", "SerialSingleton"], [206, 6, 1, "", "SerialSingletonException"], [207, 5, 1, "", "filter_ports"], [208, 5, 1, "", "get_port_from_serial_number"], [209, 5, 1, "", "get_serial_number_from_port"]], "iblrig.serial_singleton.SerialSingleton": [[205, 3, 1, "", "__init__"], [205, 3, 1, "", "__new__"], [205, 3, 1, "", "close"], [205, 3, 1, "", "open"], [205, 4, 1, "", "port"], [205, 3, 1, "", "query"], [205, 3, 1, "", "read"], [205, 3, 1, "", "to_bytes"], [205, 3, 1, "", "write"], [205, 3, 1, "", "write_packed"]], "iblrig.serial_singleton.SerialSingletonException": [[206, 3, 1, "", "__init__"], [206, 3, 1, "", "__new__"]], "iblrig.session_creator": [[211, 5, 1, "", "draw_block_len"], [212, 5, 1, "", "draw_position"], [213, 5, 1, "", "make_ephyscw_pc"]], "iblrig.sound": [[215, 5, 1, "", "configure_sound_card"], [216, 5, 1, "", "format_sound"], [217, 5, 1, "", "make_sound"]], "iblrig.tools": [[219, 1, 1, "", "ANSI"], [220, 5, 1, "", "alyx_reachable"], [221, 5, 1, "", "ask_user"], [222, 5, 1, "", "call_bonsai"], [223, 5, 1, "", "call_bonsai_async"], [224, 5, 1, "", "get_anydesk_id"], [225, 5, 1, "", "get_inheritors"], [226, 5, 1, "", "get_lab_location_dict"], [227, 5, 1, "", "internet_available"], [228, 5, 1, "", "static_vars"]], "iblrig.tools.ANSI": [[219, 2, 1, "", "BLUE"], [219, 2, 1, "", "BOLD"], [219, 2, 1, "", "CYAN"], [219, 2, 1, "", "DARKCYAN"], [219, 2, 1, "", "DIM"], [219, 2, 1, "", "END"], [219, 2, 1, "", "GREEN"], [219, 2, 1, "", "PURPLE"], [219, 2, 1, "", "RED"], [219, 2, 1, "", "UNDERLINE"], [219, 2, 1, "", "WHITE"], [219, 2, 1, "", "YELLOW"], [219, 3, 1, "", "__init__"]], "iblrig.transfer_experiments": [[230, 1, 1, "", "BehaviorCopier"], [231, 1, 1, "", "CopyState"], [232, 1, 1, "", "EphysCopier"], [233, 1, 1, "", "SessionCopier"], [234, 1, 1, "", "VideoCopier"], [235, 5, 1, "", "copy_folders"]], "iblrig.transfer_experiments.BehaviorCopier": [[230, 2, 1, "", "assert_connect_on_init"], [230, 4, 1, "", "experiment_description"], [230, 3, 1, "", "finalize_copy"], [230, 2, 1, "", "tag"]], "iblrig.transfer_experiments.CopyState": [[231, 2, 1, "", "COMPLETE"], [231, 2, 1, "", "FINALIZED"], [231, 2, 1, "", "HARD_RESET"], [231, 2, 1, "", "NOT_REGISTERED"], [231, 2, 1, "", "PENDING"], [231, 3, 1, "", "__new__"]], "iblrig.transfer_experiments.EphysCopier": [[232, 2, 1, "", "assert_connect_on_init"], [232, 3, 1, "", "initialize_experiment"], [232, 2, 1, "", "tag"]], "iblrig.transfer_experiments.SessionCopier": [[233, 3, 1, "", "__init__"], [233, 2, 1, "", "assert_connect_on_init"], [233, 3, 1, "", "copy_collections"], [233, 3, 1, "", "copy_snapshots"], [233, 4, 1, "", "experiment_description"], [233, 4, 1, "", "file_experiment_description"], [233, 4, 1, "", "file_remote_experiment_description"], [233, 3, 1, "", "finalize_copy"], [233, 3, 1, "", "get_state"], [233, 3, 1, "", "glob_file_remote_copy_status"], [233, 3, 1, "", "initialize_experiment"], [233, 4, 1, "", "remote_experiment_description_stub"], [233, 4, 1, "", "remote_session_path"], [233, 3, 1, "", "run"], [233, 4, 1, "", "state"], [233, 2, 1, "", "tag"]], "iblrig.transfer_experiments.VideoCopier": [[234, 2, 1, "", "assert_connect_on_init"], [234, 3, 1, "", "config2stub"], [234, 3, 1, "", "create_video_stub"], [234, 3, 1, "", "initialize_experiment"], [234, 2, 1, "", "tag"]], "iblrig.upgrade_iblrig": [[237, 5, 1, "", "call_subprocesses"], [238, 5, 1, "", "upgrade"]], "iblrig.valve": [[240, 1, 1, "", "Valve"], [241, 1, 1, "", "ValveValues"]], "iblrig.valve.Valve": [[240, 3, 1, "", "__init__"], [240, 4, 1, "", "calibration_date"], [240, 4, 1, "", "calibration_range"], [240, 4, 1, "", "free_reward_time_sec"], [240, 4, 1, "", "free_reward_volume_ul"], [240, 4, 1, "", "is_calibrated"], [240, 4, 1, "", "new_calibration_open_times"], [240, 4, 1, "", "settings"]], "iblrig.valve.ValveValues": [[241, 3, 1, "", "__init__"], [241, 3, 1, "", "add_samples"], [241, 3, 1, "", "clear_data"], [241, 3, 1, "", "ms2ul"], [241, 4, 1, "", "open_times_ms"], [241, 3, 1, "", "ul2ms"], [241, 4, 1, "", "volumes_ul"], [241, 4, 1, "", "weights_g"]], "iblrig.version_management": [[243, 5, 1, "", "call_git"], [244, 5, 1, "", "check_for_updates"], [245, 5, 1, "", "check_upgrade_prerequisites"], [246, 5, 1, "", "get_branch"], [247, 5, 1, "", "get_changelog"], [248, 5, 1, "", "get_commit_hash"], [249, 5, 1, "", "get_detailed_version_string"], [250, 5, 1, "", "get_local_version"], [251, 5, 1, "", "get_remote_tags"], [252, 5, 1, "", "get_remote_version"], [253, 5, 1, "", "is_dirty"]], "iblrig_tasks": [[255, 0, 0, "-", "_iblrig_tasks_ImagingChoiceWorld"], [258, 0, 0, "-", "_iblrig_tasks_advancedChoiceWorld"], [261, 0, 0, "-", "_iblrig_tasks_biasedChoiceWorld"], [264, 0, 0, "-", "_iblrig_tasks_ephysChoiceWorld"], [267, 0, 0, "-", "_iblrig_tasks_habituationChoiceWorld"], [270, 0, 0, "-", "_iblrig_tasks_neuroModulatorChoiceWorld"], [275, 0, 0, "-", "_iblrig_tasks_passiveChoiceWorld"], [278, 0, 0, "-", "_iblrig_tasks_spontaneous"], [281, 0, 0, "-", "_iblrig_tasks_trainingChoiceWorld"], [285, 0, 0, "-", "_iblrig_tasks_trainingPhaseChoiceWorld"]], "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld": [[256, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task": [[257, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session": [[257, 3, 1, "", "draw_quiescent_period"], [257, 2, 1, "", "protocol_name"]], "iblrig_tasks._iblrig_tasks_advancedChoiceWorld": [[259, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task": [[260, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session": [[260, 3, 1, "", "__init__"], [260, 3, 1, "", "draw_next_trial_info"], [260, 3, 1, "", "extra_parser"], [260, 3, 1, "", "next_trial"], [260, 2, 1, "", "protocol_name"], [260, 4, 1, "", "reward_amount"]], "iblrig_tasks._iblrig_tasks_biasedChoiceWorld": [[262, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task": [[263, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_ephysChoiceWorld": [[265, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task": [[266, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session": [[266, 3, 1, "", "__init__"], [266, 3, 1, "", "extra_parser"], [266, 3, 1, "", "get_session_template"], [266, 3, 1, "", "next_trial"], [266, 2, 1, "", "protocol_name"]], "iblrig_tasks._iblrig_tasks_habituationChoiceWorld": [[268, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task": [[269, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld": [[271, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task": [[272, 1, 1, "", "NeuroModulatorChoiceTrialData"], [273, 1, 1, "", "Session"], [274, 1, 1, "", "SessionRelatedBlocks"]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData": [[272, 2, 1, "", "choice_delay"], [272, 2, 1, "", "model_computed_fields"], [272, 2, 1, "", "model_config"], [272, 2, 1, "", "model_fields"], [272, 2, 1, "", "omit_feedback"]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session": [[273, 2, 1, "", "TrialDataModel"], [273, 3, 1, "", "__init__"], [273, 4, 1, "", "choice_to_feedback_delay"], [273, 3, 1, "", "get_state_machine_trial"], [273, 3, 1, "", "next_trial"], [273, 4, 1, "", "omit_feedback"], [273, 2, 1, "", "protocol_name"]], "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks": [[274, 3, 1, "", "__init__"], [274, 3, 1, "", "draw_reward_amount"], [274, 3, 1, "", "new_block"], [274, 3, 1, "", "next_trial"]], "iblrig_tasks._iblrig_tasks_passiveChoiceWorld": [[276, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task": [[277, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session": [[277, 3, 1, "", "__init__"], [277, 3, 1, "", "extra_parser"], [277, 3, 1, "", "get_state_machine_trial"], [277, 3, 1, "", "next_trial"], [277, 2, 1, "", "protocol_name"], [277, 3, 1, "", "start_hardware"]], "iblrig_tasks._iblrig_tasks_spontaneous": [[279, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_spontaneous.task": [[280, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_spontaneous.task.Session": [[280, 2, 1, "", "protocol_name"]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld": [[282, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task": [[283, 1, 1, "", "Session"], [284, 5, 1, "", "float_or_none"]], "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session": [[283, 3, 1, "", "extra_parser"]], "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld": [[286, 0, 0, "-", "task"]], "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task": [[287, 1, 1, "", "Session"]], "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session": [[287, 3, 1, "", "__init__"], [287, 3, 1, "", "check_training_phase"], [287, 3, 1, "", "extra_parser"], [287, 2, 1, "", "protocol_name"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "attribute", "Python attribute"], "3": ["py", "method", "Python method"], "4": ["py", "property", "Python property"], "5": ["py", "function", "Python function"], "6": ["py", "exception", "Python exception"], "7": ["py", "data", "Python data"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:attribute", "3": "py:method", "4": "py:property", "5": "py:function", "6": "py:exception", "7": "py:data"}, "terms": {"": [7, 11, 14, 22, 31, 66, 73, 75, 78, 81, 83, 84, 111, 115, 118, 126, 155, 156, 195, 196, 200, 205, 216, 227, 288, 289, 290, 291, 293, 294, 295, 296, 297, 298, 299, 300], "0": [4, 6, 7, 8, 10, 11, 12, 14, 16, 22, 24, 28, 31, 45, 55, 64, 66, 75, 76, 81, 83, 111, 115, 118, 123, 130, 148, 151, 152, 158, 159, 160, 161, 163, 170, 186, 192, 194, 213, 217, 231, 233, 241, 260, 266, 272, 277, 287, 290, 292, 293, 294, 296, 297], "00": 16, "001": [176, 293, 296, 298, 300], "002": [298, 300], "003": [298, 300], "01": [176, 217, 298, 300], "01_1_subject": [298, 300], "03": 55, "05": [16, 115], "0625": [170, 260], "0m": 219, "1": [4, 6, 8, 10, 11, 12, 16, 22, 28, 32, 55, 64, 123, 125, 126, 130, 135, 137, 140, 151, 152, 157, 159, 161, 163, 170, 177, 185, 192, 194, 205, 217, 231, 233, 257, 260, 272, 289, 290, 292, 294, 295, 298, 299, 300, 302], "10": [290, 293, 296], "100": 211, "1000": 49, "10000": 217, "102": 24, "1024": [298, 302], "11": [266, 290, 292], "11001": 163, "12": [159, 266, 293, 296], "123": [159, 224], "125": [170, 260], "1250": 45, "127": [22, 163], "1280": [298, 302], "12v": 289, "130": 64, "134": 159, "15": [45, 292], "16": 290, "16b06f60": 292, "17": 292, "180": [4, 6, 8, 10, 12, 272], "192000": 148, "1a": 289, "1b": [293, 294], "1m": 219, "1x": 290, "2": [19, 27, 37, 38, 45, 46, 55, 64, 123, 125, 130, 140, 158, 160, 170, 185, 194, 216, 217, 231, 233, 289, 290, 298, 300, 301], "20": [3, 5, 7, 11, 170, 211], "200": [28, 45], "2000": 213, "200m": [257, 293, 297], "2019": [293, 296], "2020": [176, 298, 300], "24": [161, 295], "25": [28, 170, 260], "2594": 45, "270": 159, "283185307179586": [4, 6, 8, 10, 12, 272], "2b86": [293, 296], "2d": [22, 216], "2m": 219, "3": [28, 31, 64, 123, 125, 126, 130, 185, 194, 205, 227, 231, 233, 289, 290, 291, 295], "30": [293, 294, 298, 302], "3123": 45, "33": 55, "35": [158, 260, 293, 297], "36m": 219, "37m": 219, "3b20": 292, "4": [45, 125, 130, 185, 216, 260, 274, 295], "40": 292, "400": 45, "400m": [257, 293, 297], "42": 288, "44100": [127, 217], "456": [159, 224], "4eaf": [293, 296], "4ff2": 292, "4m": 219, "5": [7, 28, 130, 135, 151, 152, 158, 170, 194, 260, 289, 290, 292, 293, 297], "50": [5, 22, 260], "5000": 217, "504": 288, "51": 24, "512": [293, 294], "53": 227, "566_265527899354975": 233, "5824": [135, 140], "5e9b7962f9a": 292, "6": [4, 6, 8, 10, 12, 22, 135, 159, 272, 292], "600": [45, 277], "64": 292, "640": [293, 294], "654": 159, "7": [45, 159, 292, 298, 300], "711": 45, "74": 152, "789": 224, "8": [159, 161, 170, 205, 227, 290, 292, 293, 295, 296], "90": [5, 77], "91m": 219, "92": [293, 296], "92m": 219, "93m": 219, "94m": 219, "95": [293, 296], "95m": 219, "96": 215, "96000": 217, "96m": 219, "99": [293, 296], "9998": 159, "A": [4, 5, 6, 7, 8, 10, 12, 14, 21, 25, 35, 37, 38, 46, 75, 77, 78, 81, 82, 84, 120, 126, 160, 161, 162, 163, 164, 165, 167, 179, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 200, 228, 234, 244, 249, 250, 252, 272, 290, 292, 298, 299, 300], "As": [293, 294], "At": [233, 293, 296, 298, 300], "BY": 22, "By": [205, 292, 298, 300], "For": [156, 257, 290, 293, 296, 297, 298, 299, 300], "If": [14, 21, 28, 31, 35, 38, 66, 70, 73, 75, 81, 83, 111, 115, 118, 126, 151, 152, 158, 160, 162, 168, 173, 175, 177, 178, 207, 221, 222, 223, 224, 227, 230, 233, 235, 237, 243, 245, 247, 250, 251, 289, 292, 293, 294, 295, 296, 298, 299], "In": [7, 14, 176, 274, 290, 292, 293, 294, 297], "It": [3, 7, 21, 25, 35, 76, 81, 82, 120, 158, 170, 227, 235, 238, 243, 245, 249, 252, 260, 289, 293, 294, 297], "Its": 295, "ONE": [14, 21, 166, 168], "On": [224, 295], "One": [14, 21, 160], "Or": 171, "The": [3, 7, 11, 14, 15, 16, 21, 26, 37, 38, 70, 73, 75, 76, 77, 81, 82, 83, 119, 120, 151, 152, 157, 158, 160, 162, 164, 166, 168, 170, 171, 173, 176, 178, 179, 186, 187, 195, 196, 198, 200, 205, 207, 208, 209, 221, 224, 227, 230, 232, 233, 234, 235, 243, 246, 247, 249, 257, 265, 274, 279, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 300, 301, 302], "Then": [292, 293, 297], "There": 290, "These": [21, 173, 292, 298, 299], "To": [173, 207, 289, 290, 292, 293, 295, 296, 298, 299, 300, 301, 302], "Will": [127, 233], "With": [290, 292, 298, 300], "_": [21, 168], "__fields__": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "__init__": [3, 5, 7, 11, 14, 20, 21, 22, 25, 49, 54, 55, 60, 62, 66, 67, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 110, 111, 112, 114, 115, 117, 118, 119, 120, 123, 124, 129, 132, 141, 142, 148, 149, 160, 161, 170, 171, 202, 203, 205, 206, 219, 233, 240, 241, 260, 266, 273, 274, 277, 287, 293, 295, 297], "__main__": [293, 297], "__name__": [293, 297], "__new__": [64, 123, 125, 130, 131, 149, 160, 205, 206, 231], "__version__": [250, 295], "_biasedchoiceworld": [293, 294], "_cl": 64, "_copy_collect": 233, "_define_messag": 288, "_devic": [298, 300], "_ephyschoiceworld": 288, "_ibl_experi": [293, 294, 298, 300], "_ibl_trainingchoiceworld2": 14, "_iblrig_taskdata": 42, "_iblrig_tasks_biasedchoiceworld": 5, "_iblrig_tasks_ephyschoiceworld": [298, 299], "_iblrig_tasks_habituationchoiceworld": 9, "_iblrig_tasks_imagingchoiceworld": [293, 297], "_iblrig_tasks_passivechoiceworld": [298, 299], "_iblrig_tasks_trainingchoiceworld": [11, 31, 298, 299], "_info": 189, "_iterate_protocol": 288, "_nn": 176, "_run": [293, 297], "_signal": 159, "a0": 67, "a6f2": [293, 296], "abc": [3, 5, 7, 9, 11, 14, 15, 16, 17, 18, 19, 21, 23, 24, 25, 26, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 200, 257, 260, 263, 266, 269, 273, 274, 277, 280, 283, 287], "abil": 288, "abl": [17, 289], "abort": 160, "about": [3, 4, 6, 7, 8, 10, 12, 120, 178, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 288, 289, 293, 294, 297], "abov": [28, 77, 289, 293, 294, 295, 298, 300], "absolut": [257, 293, 297], "abstract": [7, 14, 141, 200], "abstracteventloop": 167, "accept": [70, 288], "acceptnavigationrequest": 70, "access": [288, 298, 299, 301], "accident": 290, "accord": [11, 170, 173, 205, 266, 295, 298, 301], "accordingli": [82, 205], "account": [298, 299], "accuraci": [293, 294], "achiev": [7, 298, 299], "acquir": 294, "acquisit": [21, 37, 38, 171, 233, 234, 288, 293, 294, 297, 300], "acquisition_descript": [232, 233, 234], "acquisition_softwar": [293, 294], "across": [228, 288, 290], "act": [289, 293, 294], "action": [156, 293, 295, 296, 298, 299], "activ": [3, 81, 279, 289, 292, 295, 298, 299, 300, 301, 302], "activechoiceworld": 5, "activechoiceworldsess": [5, 7, 11, 257, 260, 263, 266, 273, 274, 283, 287], "activechoiceworldtrialdata": [3, 6, 12, 272], "actual": [15, 207, 257, 288, 289, 290, 298, 300, 302], "acut": [293, 294], "ad": [14, 21, 160, 288, 293, 294, 295, 297, 298, 302], "adapt": [11, 31, 70, 82, 260, 288, 289, 290], "adaptive_gain": [11, 31], "adaptive_reward": [11, 31], "adaptive_reward_ul": 28, "add": [14, 17, 21, 156, 228, 230, 232, 233, 234, 288, 293, 295, 297, 298, 299], "add_sampl": 241, "addit": [7, 156, 196, 237, 245, 249, 288, 289, 292, 293, 294, 295], "addition": [289, 293, 297, 298, 300], "addr": 168, "address": [168, 227, 288], "adjust": [289, 292, 295], "administ": [293, 297], "administr": [14, 288, 292], "advanc": 260, "advancedchoiceworld": 288, "advertis": 288, "affect": 292, "after": [14, 157, 160, 288, 289, 290, 292, 295, 297, 298, 299], "again": [289, 298, 299], "against": 178, "aggreg": [11, 233, 293, 296], "ago": [298, 300], "aka": 292, "algernon": [298, 299], "alia": [3, 5, 7, 9, 11, 64, 183, 273], "align": [15, 289, 293, 296, 298, 302], "aliv": [298, 299], "all": [3, 13, 14, 21, 45, 60, 111, 126, 152, 156, 159, 160, 175, 207, 225, 228, 233, 235, 274, 288, 289, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300], "all_threshold": 124, "allow": [4, 6, 8, 10, 12, 21, 70, 78, 167, 196, 228, 272, 288, 292, 298, 299, 300], "allow_reset": 238, "along": 21, "alongsid": 292, "alreadi": [14, 166, 173, 233, 247, 251, 298, 300], "also": [7, 14, 21, 173, 288, 289, 293, 294, 295, 297], "altern": [66, 75, 81, 83, 111, 115, 118, 205], "although": [298, 299], "alwai": [21, 162, 175, 183, 187], "alyx": [14, 21, 75, 78, 119, 166, 168, 195, 220, 288, 297], "alyx_cli": 119, "alyx_lab": 195, "alyx_url": 195, "alyx_us": 195, "alyxcli": [75, 119, 168], "alyxobject": 78, "alyxurl": 75, "ambient": 288, "ambient_modul": 123, "amd64": 292, "amount": [11, 26], "amount_ul": 26, "amp2x15": [193, 288, 290], "amp_typ": [193, 288, 290], "amplifi": [288, 290], "amplitud": [217, 290], "an": [14, 21, 31, 35, 75, 76, 78, 81, 82, 83, 119, 120, 125, 151, 152, 158, 159, 160, 166, 167, 168, 171, 173, 178, 186, 187, 195, 205, 207, 224, 227, 231, 234, 243, 244, 245, 250, 251, 253, 289, 296, 297, 298, 299, 300, 302], "analog": [289, 290], "angl": 22, "ani": [3, 5, 7, 11, 14, 76, 82, 83, 135, 140, 141, 154, 160, 205, 207, 222, 223, 226, 233, 237, 245, 289, 290, 292, 295, 298, 299], "annot": [4, 6, 8, 10, 12, 123, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 241, 272], "anoth": [160, 293, 294, 296, 298, 300], "anydesk": 224, "anymor": 290, "anyth": 221, "api": [21, 75, 168, 288, 292], "app": [160, 162, 165], "appdata": 292, "appear": [289, 292, 293, 295, 296], "append": [14, 73, 288, 295, 298, 299], "append_sess": 118, "appendix": [27, 289, 291], "appendtext": 73, "appli": [21, 222, 223, 293, 294, 295], "applic": [82, 293, 296], "approach": [298, 299], "appropri": [35, 178], "ar": [3, 14, 21, 38, 76, 81, 126, 156, 160, 173, 175, 176, 207, 224, 228, 233, 251, 253, 257, 265, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302], "arbitrari": [77, 288], "architectur": [279, 293, 294], "arduino": 207, "arg": [7, 9, 15, 16, 17, 19, 20, 21, 23, 54, 60, 62, 67, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 111, 115, 123, 132, 141, 142, 148, 149, 160, 202, 205, 206, 243, 245, 260, 266, 273, 274, 277, 287, 288, 293, 297], "argpars": [7, 14, 35, 156, 260, 266, 277, 283, 287], "argument": [14, 31, 35, 38, 66, 75, 77, 78, 81, 82, 83, 111, 115, 118, 155, 156, 160, 175, 177, 207, 228, 237, 243, 245, 288, 298, 300], "argumenterror": 35, "argumentlist": 292, "argumentpars": [14, 119, 155, 156], "aris": 21, "around": [2, 292], "arrai": [29, 152, 170, 216], "ask": [298, 299], "askint": 51, "assert_connect_on_init": [230, 232, 233, 234], "assert_set": 202, "assign": [160, 298, 302], "assign_callback": 21, "assist": 289, "associ": [120, 200, 207], "assort": 150, "asu": 290, "async": [160, 162, 165, 167, 223], "asynchron": [21, 160, 167, 223], "asyncio": [167, 223], "atla": 45, "attach": 289, "attempt": [75, 78, 173, 224, 227, 247, 250], "attenuation_db": 148, "attribut": [14, 66, 75, 76, 81, 83, 111, 115, 118, 181, 207, 288], "audio": [127, 288, 290, 293, 294], "auditori": 290, "authent": 75, "author": [293, 297], "auto": 288, "autobuild": 295, "autom": [288, 289, 292, 295], "automat": [28, 288, 295, 298, 299, 300], "auxiliari": 21, "avail": [21, 31, 120, 167, 173, 196, 227, 238, 244, 252, 288, 290, 292, 293, 297, 298, 299], "avoid": [158, 288, 289, 298, 300], "await": [159, 160], "az1198": 233, "b": [68, 135, 137, 140, 202, 290, 292], "b30923225609": [293, 296], "b699": 292, "ba": 45, "back": [82, 288, 289], "backend": 288, "background": 173, "backport": 290, "backsid": 290, "backup": 289, "backward": 295, "baecbddc": [293, 296], "balanc": 292, "bar": [77, 292, 293, 296], "base": [3, 5, 7, 14, 21, 70, 75, 76, 78, 81, 151, 160, 178, 207, 243, 247, 249, 288, 295], "base_biased_choice_world_param": 5, "base_choice_world": [257, 260, 263, 266, 269, 272, 273, 274, 277, 283, 287, 293, 297], "base_choice_world_param": 7, "base_parameters_fil": [5, 7, 14], "base_task": [2, 3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 280, 283, 287, 293, 297], "base_url": [166, 292], "basechoiceworld": 288, "basemodel": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 200, 272], "basesess": [3, 5, 7, 9, 11, 13, 15, 16, 17, 18, 19, 21, 23, 24, 25, 26, 119, 257, 260, 263, 266, 269, 273, 274, 277, 280, 283, 287, 293, 297], "basic": 249, "bear": [293, 297], "becaus": [7, 17], "been": [233, 251, 288, 290, 292, 293, 296, 298, 300], "beep": 24, "befor": [7, 14, 38, 160, 237, 290, 292, 293, 296, 298, 302], "behav": [76, 81], "behavior": [37, 38, 39, 230, 243, 288, 290, 291, 293, 294, 296, 298, 300], "behaviour": [3, 293, 296], "being": [70, 152, 288, 290], "believ": 292, "belli": [293, 294], "belong": [298, 299], "below": [42, 295, 298, 299, 301, 302], "best": 289, "between": [159, 160, 257, 288, 289, 290, 292, 293, 297], "beyond": 196, "bias": [3, 5, 151, 152, 213, 260, 265], "biasedchoiceworld": [3, 260, 293, 294], "biasedchoiceworldsess": [257, 263, 266, 273, 274, 293, 297], "biasedchoiceworldtrialdata": [5, 272], "biasedcw": 257, "bin": [217, 293, 294], "binari": 216, "bit": 292, "bit_depth": 148, "black": [289, 295], "blk": 289, "block": [3, 5, 21, 70, 73, 160, 170, 202, 213, 224, 260, 274], "block_init_5050": 5, "block_num": [6, 272], "block_trial_num": [6, 272], "blue": [219, 289], "bnc": [289, 290], "board": [289, 290], "bodi": [28, 298, 302], "bold": 219, "bonsai": [16, 22, 173, 187, 222, 223, 288, 291, 292, 298, 302], "bonsai_workflow": [189, 298, 302], "bonsairecordingmixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "bonsaivisualstimulusmixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "bool": [4, 6, 8, 10, 12, 14, 21, 37, 38, 49, 64, 70, 75, 77, 81, 115, 117, 118, 119, 120, 123, 126, 132, 145, 148, 160, 161, 162, 165, 166, 168, 178, 184, 195, 202, 203, 205, 220, 221, 222, 223, 224, 227, 230, 232, 233, 234, 235, 237, 238, 240, 243, 244, 248, 253, 272, 277], "boolean": [75, 244], "bootstrap": [222, 223], "border": 15, "both": [76, 81, 159, 171, 177, 207, 288, 295, 298, 300, 302], "bottom": 289, "bound": [66, 75, 81, 83, 111, 115, 118], "box": 288, "bpod": [3, 7, 20, 24, 26, 171, 198, 217, 230, 288, 289, 291, 293, 294, 296, 297, 298, 299], "bpod_bas": 123, "bpod_com_protocol": 123, "bpod_com_protocol_modul": 123, "bpod_data": [3, 7, 14, 170, 171, 198], "bpod_io": 123, "bpod_ttl_test_d": 185, "bpod_ttl_test_statu": 185, "bpodbas": 123, "bpodcomprotocol": 123, "bpodcomprotocolmodul": 123, "bpodio": 123, "bpodmixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "bpodmodul": 123, "brain": [45, 152, 279, 291, 292, 298, 299, 301], "branch": [246, 247, 289, 292, 295], "break": [292, 295], "bright": 289, "broken": [150, 249, 257], "browser": 70, "bug": 292, "bugfix": [288, 295], "build": 217, "bulk": 160, "bunch": [14, 119], "bunchmodel": [184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195], "bundl": 289, "button": [81, 288, 289, 292, 298, 299], "byte": [135, 137, 140, 141, 202, 205, 216, 222], "bytestr": 205, "c": [22, 66, 75, 76, 81, 83, 111, 115, 118, 137, 156, 175, 289, 290, 293, 295, 296, 297, 298, 299, 300, 301, 302], "cabl": [289, 290], "cach": [75, 166, 227, 243, 247, 288], "cache_output": 243, "cachetoken": 75, "calcul": 152, "calibr": [49, 115, 288, 289], "calibration_d": 240, "calibration_finish": 115, "calibration_rang": 240, "call": [7, 14, 17, 21, 160, 222, 223, 228, 237, 243, 245, 257, 288, 298, 300, 302], "callabl": [17, 82, 123, 245], "callback": [21, 160, 168], "calledprocesserror": [222, 224, 237], "camera": [14, 15, 159, 163, 186, 187, 234, 288, 293, 294, 298, 302], "camera_config": 14, "camera_record": [289, 298, 302], "camera_setup": [298, 302], "can": [3, 7, 13, 76, 81, 150, 159, 171, 173, 220, 233, 243, 289, 290, 293, 294, 295, 296, 297, 298, 301, 302], "can_control_l": 123, "cancel": 160, "cannot": [28, 246, 248, 249, 252, 290, 293, 294], "capabl": 290, "carandiniharris_midbrain_ibl": [293, 294], "card": [24, 127, 215, 216, 289, 290], "carri": [75, 81, 83], "case": [21, 221, 288, 293, 297], "cast": 183, "catastroph": 290, "caus": [159, 288, 289, 290], "causion": 159, "cd": [292, 298, 299, 301, 302], "ceil": 28, "center": 288, "certain": 292, "cf": 290, "chan": 217, "chang": [75, 77, 81, 150, 170, 253, 257, 288, 289, 293, 295, 297, 298, 299], "changelog": [120, 247, 295], "channel": [22, 186, 217, 293, 294], "charact": [73, 205], "characterist": 3, "check": [11, 35, 158, 160, 162, 220, 222, 227, 233, 238, 244, 245, 248, 253, 288, 289, 295, 298, 299], "check_audio_pre_tri": [293, 296], "check_correct_trial_event_sequ": [293, 296], "check_detected_wheel_mov": [293, 296], "check_error_trial_event_sequ": [293, 296], "check_errorcue_delai": [293, 296], "check_gocue_delai": [293, 296], "check_iti_delai": [293, 296], "check_n_trial_ev": [293, 296], "check_negative_feedback_stimoff_delai": [293, 296], "check_positive_feedback_stimoff_delai": [293, 296], "check_response_feedback_delai": [293, 296], "check_response_stimfreeze_delai": [293, 296], "check_reward_volum": [293, 296], "check_reward_volume_set": [293, 296], "check_stimfreeze_delai": [293, 296], "check_stimoff_delai": [293, 296], "check_stimoff_itiin_delai": [293, 296], "check_stimon_delai": [293, 296], "check_stimon_gocue_delai": [293, 296], "check_stimulus_move_before_gocu": [293, 296], "check_sync_puls": 7, "check_training_phas": [11, 287], "check_trial_length": [293, 296], "check_wheel_freeze_during_quiesc": [293, 296], "check_wheel_integr": [293, 296], "check_wheel_move_before_feedback": [293, 296], "check_wheel_move_during_closed_loop": [293, 296], "checkmark": 78, "checkout": 292, "child": [14, 293, 294, 297], "choic": [2, 5, 11, 27, 170, 260, 265, 288, 290], "choice_delai": 272, "choice_to_feedback_delai": 273, "choice_world_visual_stimulu": 16, "choiceworld": 260, "choiceworldsess": [3, 5, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "choiceworldtri": [293, 297], "choiceworldtrialdata": [4, 6, 7, 10, 12, 272], "choiceworldtrialstimelin": [293, 294], "chrono": [293, 294], "ci": [288, 295], "cl": [123, 160, 205, 225], "class": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 48, 49, 53, 54, 55, 59, 60, 61, 62, 63, 64, 65, 66, 67, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 122, 123, 124, 125, 128, 129, 130, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 147, 148, 150, 159, 160, 161, 162, 169, 170, 171, 178, 181, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 199, 200, 201, 202, 203, 204, 205, 218, 219, 225, 229, 230, 231, 232, 233, 234, 239, 240, 241, 256, 257, 259, 260, 262, 263, 265, 266, 268, 269, 271, 272, 273, 274, 276, 277, 279, 280, 282, 283, 286, 287, 293, 297], "classmethod": [14, 187, 195, 196], "classvar": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "clean": [21, 160, 253, 288, 299], "cleanup": [160, 298, 300], "cleanup_mixin_network": 21, "cleanup_week": 38, "clear": [73, 112, 114, 160], "clear_calibr": 115, "clear_crop_callback": 115, "clear_data": 241, "clear_drop": 115, "clear_message_queu": 160, "clearli": 196, "cli": [219, 288, 298, 299, 302], "click": [70, 81, 289, 292, 293, 295, 296, 298, 299], "clickedwhileact": 81, "clickedwhileinact": 81, "client": [22, 160], "clipboard": 73, "clock": [293, 294, 296], "clone": 292, "close": [60, 123, 160, 167, 205, 288, 295, 298, 299], "close_time_": 123, "closeev": [115, 118], "code": [27, 73, 130, 219, 222, 237, 288, 293, 295, 296, 297], "collat": 160, "collect": [14, 150, 176, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 233, 234, 289, 293, 294, 298, 300], "collection_nam": 176, "color": [55, 73, 77, 114, 170, 288, 293, 296], "colornam": 73, "column": [76, 196], "columncount": 76, "com": [70, 82, 124, 126, 152, 162, 208, 209, 290, 292, 298, 301], "com1": 126, "com2": 126, "com3": [126, 205], "com_bpod": 185, "com_f2ttl": 188, "com_rotary_encod": 190, "com_scal": [184, 191], "com_sound": [193, 290], "combin": [205, 288, 293, 295, 297], "combinatori": [293, 297], "come": [3, 167, 289, 290, 293, 297], "command": [175, 224, 237, 243, 288, 292, 293, 295, 296, 297], "commandlin": 288, "commit": [248, 249, 289], "common": [13, 14, 150, 289, 293, 294], "commun": [21, 22, 82, 83, 126, 159, 160, 162, 165, 205, 208, 209, 288, 290], "compar": [162, 244], "compat": [179, 288, 292, 295], "complain": 289, "complet": [28, 83, 231, 233, 292, 293, 294, 298, 299, 300], "completedprocess": [222, 223], "complic": [11, 293, 297], "compon": [200, 288, 290], "compos": [13, 293, 297], "comprehens": 289, "comput": [3, 4, 6, 8, 10, 11, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 233, 272, 288, 289, 290, 292, 293, 294, 296, 300, 301], "compute_end_session_criteria": 170, "compute_perform": 11, "compute_reward_tim": 26, "computedfieldinfo": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "comx": 290, "concern": 290, "conclud": [293, 297], "concurr": 82, "condit": [49, 207, 288], "config": [4, 6, 8, 10, 12, 15, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 234, 272], "config2stub": 234, "configdict": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "configur": [4, 6, 8, 10, 12, 14, 78, 127, 159, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 234, 272, 274, 289, 293, 297, 298, 299, 301, 302], "confirm": [238, 298, 299, 300], "confirmed_send": 159, "conform": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 290], "conjunct": 171, "connect": [14, 21, 78, 124, 160, 205, 220, 227, 245, 288, 289, 290, 293, 297, 298, 299], "connectionerror": 245, "connector": 290, "consecut": [293, 294], "consolid": 288, "constant": [76, 81], "constraint": 3, "construct": [14, 178, 298, 299], "constructor": [14, 38, 78, 81, 111, 293, 297], "consum": 290, "contact": 289, "contain": [5, 7, 14, 21, 168, 170, 176, 178, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 198, 244, 249, 288, 293, 294, 298, 300], "content": [73, 293, 294, 295], "context": 292, "contigu": 216, "conting": [22, 170, 288], "continu": [224, 290, 292], "contrast": [4, 6, 8, 10, 11, 12, 22, 151, 170, 213, 260, 272, 288], "contrast_set": [33, 151, 170, 260], "contribut": [293, 296], "control": [173, 288, 289, 292, 295], "controller2model": 118, "convent": [205, 293, 294, 297], "convers": 35, "convert": [26, 35, 205, 288], "convert_ui": 288, "coordin": 45, "copi": [17, 38, 73, 233, 235, 288, 292, 293, 294, 296], "copier": [38, 233], "copy_collect": 233, "copy_snapshot": 233, "copyst": 233, "copytoclipboard": 73, "corner": 289, "correct": [3, 288, 289, 292], "correctli": [159, 289], "correspond": [4, 6, 8, 10, 11, 12, 17, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 207, 209, 272, 293, 295, 296], "corrupt": 288, "could": [66, 75, 81, 83, 111, 115, 118], "count": [157, 170, 293, 297], "counter": 170, "cover": [288, 293, 297], "coverag": 295, "cp": 292, "crash": 288, "creat": [14, 21, 64, 75, 120, 160, 173, 196, 210, 213, 217, 279, 292, 295, 298, 300], "create_sess": 14, "create_video_stub": 234, "creation": [288, 298, 300], "credenti": [298, 299], "critera": 170, "criteria": [207, 288, 293, 296], "critic": [77, 293, 296], "cross": 167, "ctrl": 171, "cue": 290, "cumul": 28, "current": [7, 14, 22, 24, 75, 78, 160, 162, 167, 224, 233, 247, 248, 289, 295, 298, 299], "custom": [70, 77, 78, 296], "custom_task": 288, "cyan": 219, "d": 295, "daemon": 160, "dai": 14, "daili": 28, "damag": 289, "daq": [186, 293, 296], "dark": [49, 289], "darkcyan": 219, "data": [3, 4, 6, 8, 10, 12, 14, 21, 25, 26, 37, 38, 39, 40, 41, 76, 111, 148, 163, 164, 168, 170, 171, 176, 178, 180, 195, 196, 198, 205, 233, 279, 288, 293, 294, 296, 299, 302], "data_fram": 76, "data_specifi": 205, "databas": [166, 168, 195, 293, 297, 298, 299], "dataclass": 129, "datafram": [76, 170, 171, 196, 198, 266], "date": [21, 154, 185, 188, 192, 194, 240], "dead": 288, "deadlock": 288, "deal": 150, "debia": 287, "debias": 260, "debias_tri": 12, "debug": [118, 222, 223, 288], "decai": 217, "decent": 292, "decid": [70, 290], "decim": 288, "decis": [3, 291], "decod": 224, "decor": [76, 81, 228], "dedic": 290, "deduc": [11, 178], "deem": 295, "deeper": [293, 297], "def": [293, 297], "default": [4, 5, 6, 7, 8, 10, 12, 14, 21, 26, 31, 51, 70, 73, 76, 77, 81, 127, 151, 152, 156, 158, 163, 164, 173, 175, 178, 184, 185, 186, 187, 191, 192, 193, 194, 195, 196, 198, 205, 216, 217, 221, 222, 223, 224, 227, 235, 243, 248, 272, 292, 293, 294, 296, 298, 300, 302], "default_reward": 31, "default_reward_amount": [7, 11], "defin": [4, 6, 8, 10, 12, 14, 21, 76, 81, 164, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 233, 260, 272, 274, 288, 293, 294, 296, 298, 299], "define_and_start_state_machin": 115, "define_harp_sounds_act": 123, "define_rotary_encoder_act": 123, "define_xonar_sounds_act": 123, "definit": [217, 288], "delai": 288, "delay_sec": [7, 288], "delay_to_stim_cent": 10, "deleg": [70, 288], "delet": [288, 298, 300], "deliv": [170, 290], "deliverd": 28, "delivered_volume_ul": 28, "depend": [3, 24, 288, 290], "depth": 45, "describ": [66, 75, 81, 83, 111, 115, 118, 205, 295, 298, 301], "descript": [14, 21, 27, 31, 177, 186, 187, 195, 230, 232, 233, 234, 288, 297, 298, 300], "description_ephyspc": [298, 300], "description_taskpc": [298, 300], "design": [76, 81, 82, 249, 290, 298, 299], "desir": [7, 15, 292, 298, 299], "destination_fold": 14, "detail": [7, 178, 249, 293, 294, 295], "detect": [288, 289], "determin": [21, 163, 244, 246, 248, 253, 292, 293, 294], "dev": [205, 298, 299], "develop": [84, 289], "deviat": 157, "devic": [14, 21, 160, 162, 163, 164, 166, 205, 207, 208, 209, 230, 232, 233, 234, 288, 289, 290, 298, 302], "device_bpod": 184, "device_camera": [14, 184, 234, 298, 302], "device_frame2ttl": 184, "device_microphon": 184, "device_rotary_encod": 184, "device_scal": 184, "device_screen": 184, "device_sound": [184, 288, 290], "device_valv": 184, "df": 76, "diagram": [7, 293, 296], "dialog": [111, 120, 173, 288], "dict": [3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 15, 17, 21, 31, 75, 77, 78, 81, 82, 118, 123, 135, 137, 140, 141, 153, 160, 161, 163, 164, 166, 168, 171, 175, 177, 179, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 207, 222, 223, 226, 233, 234, 272, 288], "dictionari": [4, 6, 7, 8, 10, 11, 12, 14, 17, 31, 45, 123, 156, 163, 164, 175, 177, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 234, 272], "dictionri": 17, "diff": 253, "differ": [7, 66, 75, 81, 83, 111, 115, 118, 260, 289, 298, 300], "digit": [288, 290, 292], "digraph": 7, "dim": 219, "dir": 195, "direct": [225, 289], "directli": [298, 299], "directori": [14, 35, 77, 175, 235, 253, 292, 295, 298, 300, 301, 302], "dirti": [249, 253, 288, 295], "disabl": 288, "disable_behavior_input_port": [185, 288], "disconnect": 290, "discov": 292, "discuss": [298, 299], "disk": [77, 162, 288, 293, 297], "dispatch": 160, "dispens": 26, "displac": 22, "displai": [7, 78, 120, 170, 221, 288, 289, 293, 295, 296, 298, 299, 301], "display_full_json": 171, "display_idx": [192, 289], "display_scale_st": 115, "display_scale_text": 115, "displayrol": 76, "disregard": 60, "distinct": [293, 297, 298, 299], "distribut": [151, 158, 257, 289, 293, 297], "dn": 227, "do": [37, 38, 162, 233, 288, 289, 290, 295, 298, 299], "do_cach": 119, "do_rais": [178, 202], "doc": [76, 81, 205, 288, 295], "doct": 171, "document": [16, 288, 291, 293, 296, 298, 301], "doe": [35, 70, 162, 173, 207, 222, 223, 237, 251, 260, 279, 289, 290, 295, 298, 299], "doesn": [14, 25, 298, 300], "domain": 227, "don": [233, 288, 289, 292], "done": [14, 15, 293, 296], "dose": 28, "dot": 295, "doubl": [257, 289, 293, 297], "down": [288, 290, 298, 299], "downgrad": 292, "download": 292, "draw": [7, 151, 257, 288, 293, 297], "draw_next_trial_info": [7, 9, 260], "draw_quiescent_period": [257, 293, 297], "draw_reward_amount": 274, "drawback": 290, "drawn": [151, 152, 213], "drive": [293, 297], "driver": [289, 290], "drop": 288, "drop_clear": 115, "dry": [37, 38, 298, 300], "dud": 288, "due": [160, 288], "dump": 171, "durat": [123, 217, 288, 293, 297], "duration_": 115, "duration_sec": 25, "duration_spontan": 277, "dure": [28, 83, 171, 245, 253, 288, 289, 290, 292, 293, 294, 297], "dynam": [17, 289], "e": [14, 21, 22, 37, 38, 152, 159, 163, 205, 217, 224, 292, 293, 294, 295, 296, 298, 300, 302], "each": [11, 14, 17, 21, 66, 75, 81, 83, 111, 115, 118, 160, 196, 198, 207, 293, 294, 295, 296, 297, 298, 300, 302], "earlier": [233, 292], "eas": 288, "easi": [293, 297], "easili": [289, 293, 296], "echo": 159, "echoprotocol": [162, 165], "edit": [78, 292], "editor": [222, 223, 288, 290, 292], "effect": 290, "eid": [293, 296], "either": [3, 21, 66, 75, 76, 81, 83, 111, 115, 118, 171, 243, 247], "electr": 289, "electrophysiologi": [46, 293, 294, 298, 301], "element": [152, 244], "ellipsi": 76, "embodi": 11, "emit": [75, 81, 82, 83], "emploi": 289, "empti": [18, 171, 224, 298, 300], "emul": 290, "enabl": [222, 223, 293, 295, 296, 298, 299], "encod": [23, 288, 293, 297], "encompass": [298, 299], "end": [219, 233, 288, 289, 290, 293, 297], "enhanc": [298, 299], "enough": 289, "ensur": [173, 179, 233, 289, 292], "enter": [36, 221, 298, 299], "entri": [42, 82, 288, 293, 297], "enum": [125, 130, 231], "enumer": [125, 231], "env": [292, 293, 296], "environ": [245, 292, 295, 298, 299], "ephi": [37, 38, 40, 210, 232, 265, 288, 290, 293, 294, 298, 299, 300, 301, 302], "ephyscw": 213, "ephyspc": [298, 300], "ephysrig_setupcamera": [298, 302], "equal": [158, 298, 299], "equip": 290, "equiprob": 3, "errand": [293, 297], "error": [3, 24, 35, 82, 83, 160, 178, 224, 230, 232, 233, 234, 243, 250, 251, 253, 288, 289], "essenti": [293, 296], "establish": [21, 160, 227, 293, 297], "et": [293, 297], "etc": [37, 38, 45, 173, 216, 298, 302], "ethernet": 290, "even": 227, "event": [22, 60, 115, 118, 153, 160, 167, 288, 293, 296, 297], "event_error": 7, "event_reward": 7, "eventfilt": [60, 118], "eventu": 295, "everi": 274, "everyth": 14, "ex": [126, 289, 292], "exactli": 21, "exampl": [22, 45, 156, 175, 288, 292, 294, 296, 301, 302], "except": [21, 31, 83, 128, 129, 131, 147, 149, 160, 178, 204, 206, 224, 243, 245, 265, 288], "exception_handl": 245, "exclud": 13, "execut": [82, 126, 222, 223, 224, 237, 243, 253, 289, 292, 293, 297, 298, 299, 300], "executionpolici": 292, "exhaust": 175, "exist": [14, 35, 75, 76, 81, 162, 171, 173, 183, 207, 222, 223, 233, 235, 288, 290, 293, 295, 297, 298, 300], "exit": [14, 22, 160, 222, 288, 292], "exp": [159, 257, 293, 297], "exp_ref": [14, 21, 159, 161], "expcleanup": 160, "expect": [14, 21, 207, 221, 230, 292, 293, 296, 298, 302], "expected_respons": 202, "expend": 21, "experi": [14, 21, 31, 160, 161, 177, 230, 232, 233, 234, 289, 297, 300, 302], "experienc": 290, "experiment": [293, 297], "experiment_descript": [14, 31, 161, 177, 230, 233], "expinfo": [21, 159], "expinit": 21, "explicitli": [7, 14], "explor": [274, 292], "explos": [293, 297], "expmessag": [21, 159, 160], "exponenti": 158, "export": [24, 66, 75, 81, 83, 111, 115, 118, 295], "expos": 14, "express": [123, 126, 207], "expstart": 21, "expstatu": 159, "ext_messag": 129, "extend": [2, 4, 6, 10, 12, 196, 205], "extens": [289, 293, 294], "extra": [4, 6, 8, 10, 12, 14, 119, 196, 272, 288], "extra_arg": 156, "extra_info": [3, 5, 7, 11], "extra_pars": [7, 14, 260, 266, 277, 283, 287, 293, 297], "extract": [14, 25, 293, 294, 296, 297], "extractor": [14, 292, 293, 294, 297], "extractor_task": [14, 293, 297], "f": 22, "f2ttl_calibration_d": 188, "f2ttl_dark_thresh": 188, "f2ttl_light_thresh": 188, "face": 289, "factor": [211, 293, 297], "factori": 161, "fade": 217, "fail": [14, 21, 75, 130, 160, 178, 233, 243, 247, 249, 250, 288, 293, 296], "failur": [224, 290], "fall": 158, "fallback": 175, "fals": [4, 6, 8, 10, 12, 14, 21, 37, 38, 49, 51, 64, 70, 75, 76, 81, 115, 117, 118, 119, 123, 124, 126, 132, 145, 148, 156, 160, 161, 162, 165, 178, 184, 185, 186, 187, 191, 192, 193, 194, 195, 202, 203, 216, 220, 221, 222, 223, 224, 227, 230, 235, 237, 238, 253, 260, 272, 277, 288], "faq": 70, "far": [166, 233], "faulti": 289, "fdel": [76, 81], "featur": [15, 288, 295, 298, 299], "fed": 156, "feedback": 24, "fetch": [37, 38, 160, 247, 251, 252, 288, 292], "few": [289, 293, 297], "fget": [76, 81], "fiber": [293, 294], "fidel": 290, "field": [4, 6, 8, 10, 12, 64, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 288, 295, 298, 299], "fieldinfo": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "figur": [170, 171], "file": [5, 7, 14, 21, 37, 38, 150, 159, 162, 163, 164, 165, 171, 173, 175, 178, 179, 183, 187, 198, 216, 217, 222, 223, 230, 232, 233, 234, 235, 247, 265, 288, 295, 297, 298, 299, 300, 301, 302], "file_experiment_descript": 233, "file_hardware_set": [14, 119], "file_iblrig_set": [14, 21, 119], "file_json": 171, "file_jsonable_fixtur": 7, "file_path": 216, "file_remote_experiment_descript": 233, "file_task_data": [31, 177], "filenam": [178, 179, 180, 288, 298, 300], "filenotfounderror": [126, 162, 173, 222, 223, 224, 237], "filepath": [154, 292], "filter": [207, 298, 299], "final": [14, 76, 81, 231, 233, 290, 293, 296, 297], "finalize_copi": [230, 233], "find": [224, 290, 293, 295, 296], "fine": [289, 290], "finicki": 289, "finish": [83, 222, 288], "finit": [290, 291], "first": [5, 11, 14, 45, 123, 245, 292, 293, 295, 297], "fit": 288, "fix": [260, 288, 295], "fixtur": [265, 266, 288], "flag": [76, 81, 288, 295, 298, 299, 300], "flake8": 288, "flash": 289, "flat": 216, "flathead": 290, "flexibl": [293, 297], "flir": 289, "float": [4, 6, 8, 10, 12, 22, 26, 30, 31, 33, 55, 115, 119, 123, 148, 151, 152, 157, 158, 160, 171, 192, 194, 202, 203, 217, 240, 241, 257, 260, 272, 284], "floor": 28, "flow": 7, "flush": [118, 123], "fn": 82, "focu": 15, "folder": [14, 21, 37, 38, 164, 174, 176, 195, 233, 235, 288, 293, 294, 295, 297, 298, 299, 300, 301], "folder_not_in_desc_fil": [298, 300], "follow": [3, 175, 205, 245, 289, 290, 292, 293, 294, 296, 297, 298, 299, 300], "font": 73, "fontsiz": 73, "fool": [293, 297], "forc": [227, 288, 292], "force_upd": 227, "forecast": [293, 297], "foreground": 73, "form": [166, 177], "format": [7, 21, 83, 198, 205, 216, 219, 224, 249, 288, 293, 294], "format_id": 224, "format_str": 205, "found": [31, 35, 73, 126, 154, 177, 208, 224, 233, 234, 237, 292, 293, 294, 295, 296, 298, 301], "fp": [186, 293, 294, 298, 302], "frame": [19, 70, 186, 288, 298, 302], "frame2ttl": [86, 288], "frame2ttlmixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "framework": [293, 297], "free": 288, "free_reward": 119, "free_reward_tim": 119, "free_reward_time_sec": 240, "free_reward_volume_ul": [194, 240], "freez": 288, "freeze_reward": 288, "frequenc": [22, 217], "frequent": 150, "freset": [76, 81], "friendli": [200, 298, 299], "from": [3, 4, 6, 7, 8, 10, 12, 14, 21, 26, 37, 38, 70, 82, 111, 151, 154, 155, 158, 159, 160, 163, 164, 166, 167, 171, 173, 175, 177, 178, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 205, 217, 233, 234, 235, 247, 249, 252, 257, 260, 266, 272, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302], "front": 289, "fset": [76, 81], "ftp": 292, "full": [14, 42, 164, 171, 195, 198, 216, 293, 297], "fulli": [293, 294, 297, 298, 300], "func": [8, 22, 183, 187], "function": [17, 27, 34, 35, 44, 45, 50, 56, 63, 74, 76, 81, 82, 116, 122, 128, 150, 155, 158, 159, 167, 172, 173, 175, 178, 187, 197, 202, 204, 207, 208, 210, 214, 218, 221, 224, 227, 228, 229, 235, 236, 237, 238, 242, 243, 244, 245, 247, 249, 250, 251, 252, 282, 293, 297, 298, 299], "further": [290, 295], "fv": 233, "g": [14, 22, 37, 38, 159, 163, 203, 205, 224, 293, 294, 298, 300, 302], "gabor": 22, "gain": [11, 22, 31, 124, 288], "gallop": 288, "garbor": 288, "gaussian": 22, "ge": [4, 6, 8, 10, 12, 185, 192, 194, 241, 272], "gener": [3, 5, 7, 9, 11, 20, 24, 26, 82, 132, 145, 152, 158, 207, 210, 213, 234, 249, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287, 288, 293, 295, 297], "gentli": 289, "get": [7, 11, 14, 25, 31, 76, 119, 123, 200, 205, 233, 246, 248, 288, 289, 293, 296, 298, 301], "get_ambient_sensor_read": 123, "get_exp_info": 21, "get_gram": 202, "get_graphviz_task": 7, "get_local_and_remote_path": [31, 177], "get_modul": 123, "get_next_calibration_tim": 115, "get_scale_read": 115, "get_sess": 119, "get_session_templ": 266, "get_stable_gram": 202, "get_stat": 233, "get_state_machine_tri": [7, 9, 273, 277], "get_subject_training_info": 11, "get_task_argu": [293, 297], "get_task_directori": 14, "get_task_extra_pars": 119, "get_task_fil": 14, "get_task_paramet": 119, "getdevic": 80, "getter": [14, 21], "git": [237, 238, 243, 245, 246, 247, 249, 251, 252, 253, 292, 295], "github": [152, 247, 289, 292, 295, 298, 299, 301], "give": [7, 293, 294], "given": [26, 76, 77, 119, 151, 166, 173, 176, 177, 293, 294, 296, 298, 300], "glob": 288, "glob_file_remote_copy_statu": 233, "gnd": 289, "go": [28, 293, 297], "go_tone_index": 123, "goe": 31, "googl": 227, "googledr": 289, "gpio": 186, "grace": 14, "grade": 290, "gram": [28, 202], "graphic": 171, "great": 150, "greater": 158, "green": [219, 293, 296], "group": 157, "gt": [4, 6, 8, 10, 12, 123, 186, 192, 194, 241, 272], "guarante": 290, "gui": [21, 288, 293, 297, 298, 299, 301], "guid": [298, 299], "guidelin": 289, "h": 22, "ha": [3, 5, 11, 14, 81, 83, 152, 175, 213, 233, 253, 288, 290, 292, 293, 297], "habitu": 3, "habituationchoiceworldsess": 269, "habituationchoiceworldtrialdata": 9, "half": 213, "halt": [293, 297], "hand": 289, "handl": [22, 70, 160, 243, 245, 288, 295], "handler": [14, 17, 22], "handshak": [49, 148], "happen": [293, 297], "happi": [298, 299], "hard": [24, 290], "hard_reset": 231, "hardwar": [7, 13, 14, 130, 288, 293, 297], "hardware_set": [14, 54, 111, 112, 118, 132, 145, 184, 226, 234, 288, 289, 290, 292, 298, 302], "hardware_settings_templ": 292, "hardwareset": [14, 54, 111, 112, 118, 132, 145, 178, 226], "hardwaresettingsbpod": 184, "hardwaresettingscamera": 184, "hardwaresettingscameraworkflow": 184, "hardwaresettingsframe2ttl": 184, "hardwaresettingsmicrophon": 184, "hardwaresettingsrotaryencod": 184, "hardwaresettingsscal": 184, "hardwaresettingsscreen": 184, "hardwaresettingssound": 184, "hardwaresettingsvalv": [184, 240], "harp": [127, 193, 289, 290], "hasbpod": [3, 5, 7, 9, 11, 24, 26, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "hash": 248, "have": [17, 25, 251, 288, 289, 290, 292, 293, 294, 295, 296, 298, 299, 300], "haven": 288, "hd": 290, "header": 76, "headerdata": 76, "hear": 290, "height": [55, 186, 293, 294, 298, 302], "help": [289, 293, 295, 296, 298, 300], "here": [17, 289, 292, 293, 294, 295, 296, 297], "hesit": [289, 292], "hidden": 64, "hierarch": [293, 297], "hierarchi": 14, "hifi": [127, 193, 288, 289], "high": 290, "hight": 186, "hint": 288, "histori": [31, 288], "hit": 36, "hoferlab": 288, "hold": [129, 289], "home": [5, 7, 175], "hood": 288, "hook": 295, "host": [168, 227, 289], "hostnam": 162, "hot": 288, "hotfix": 288, "hover": [293, 296], "how": [160, 298, 300, 301, 302], "howev": [14, 233, 292, 293, 297], "html": [205, 292, 295], "htmlcov": 295, "http": [70, 82, 152, 205, 292, 298, 301], "hz": [217, 298, 302], "i": [3, 5, 7, 9, 11, 14, 15, 16, 17, 21, 25, 28, 31, 35, 66, 70, 73, 75, 76, 77, 81, 82, 83, 111, 115, 118, 120, 126, 151, 152, 154, 155, 158, 160, 162, 164, 165, 167, 170, 171, 173, 176, 178, 183, 196, 202, 205, 221, 222, 223, 224, 227, 230, 233, 235, 237, 243, 244, 245, 247, 248, 249, 251, 253, 257, 260, 265, 273, 274, 279, 288, 289, 290, 291, 292, 294, 295, 297, 298, 299, 300, 301, 302], "ibl": [290, 291, 293, 297], "ibl_mesoscope_act": [293, 294], "ibl_neuropixel_brainwide_01": [293, 294], "iblenv": 292, "ibllib": [14, 293, 296], "iblregistrationcli": 14, "iblrig": [257, 260, 263, 266, 269, 272, 273, 274, 277, 280, 283, 287, 288, 289, 290, 293, 295, 296, 297, 299, 300, 301, 302], "iblrig_custom_task": [293, 297], "iblrig_data": 175, "iblrig_local_data_path": 195, "iblrig_local_subjects_path": 195, "iblrig_param": 292, "iblrig_remote_data_path": 195, "iblrig_remote_subjects_path": 195, "iblrig_set": [14, 37, 38, 79, 111, 118, 132, 145, 163, 164, 175, 177, 195, 226, 292, 298, 299, 300, 301, 302], "iblrig_settings_templ": 292, "iblrig_task": [298, 299], "iblrigv8": [171, 289, 290, 295, 299, 300, 302], "iblrigv8_data": [175, 293, 296], "iblrigv8dev": 295, "iblutil": [21, 160, 162, 165, 288], "icon": 78, "id": [224, 266, 288], "ideal": 289, "ident": 290, "identifi": [208, 209, 252, 289, 290, 293, 297, 298, 300], "idx": [111, 151, 152], "idx_prob": 151, "ignor": [21, 235, 288, 298, 300], "imag": [293, 294], "imped": 290, "implement": [7, 14, 70, 170, 171, 260, 288, 291, 293, 295, 296, 297], "import": [127, 292, 293, 294, 297], "improv": [288, 292], "inact": 81, "includ": [7, 157, 195, 249, 288, 293, 294, 295, 297, 298, 300], "include_launch": 292, "include_test": 292, "incompat": 295, "incomplet": [292, 298, 300], "inconsist": 288, "incorpor": 7, "incorrect": 288, "increas": [28, 288, 290], "increasingli": 290, "increment": 295, "independ": [298, 300], "index": [65, 76, 148, 151, 152, 186, 215, 295, 298, 302], "indexerror": 152, "indic": [35, 70, 75, 77, 78, 120, 196, 202, 244, 289, 295, 298, 300], "individu": [66, 75, 81, 83, 111, 115, 118, 290], "infer": [288, 295], "infinit": [158, 159], "info": [7, 14, 31, 130, 159, 198, 288, 293, 296], "inform": [3, 7, 14, 16, 77, 120, 161, 177, 244, 249, 288, 293, 294, 296, 298, 299, 300, 301], "infrastructur": [293, 297], "inherit": 17, "inheritor": 225, "init": [21, 22, 159, 233], "init_mixin_bonsai_record": 15, "init_mixin_bonsai_visual_stimulu": 16, "init_mixin_bpod": 17, "init_mixin_frame2ttl": 19, "init_mixin_network": 21, "init_mixin_rotary_encod": 23, "init_mixin_sound": 24, "init_mixin_valv": 26, "initi": [21, 66, 75, 77, 78, 81, 82, 196, 228, 233, 288, 293, 297, 298, 299, 300, 301, 302], "initial_gram": 115, "initialize_experi": [232, 233, 234], "initialize_scal": 115, "initstyleopt": 65, "input": [50, 78, 156, 167, 175, 288, 289], "inspect": [293, 296], "instal": [238, 243, 244, 245, 246, 247, 248, 249, 251, 252, 288, 291, 293, 297, 299, 301], "install_pyspin": [292, 298, 302], "install_spinnak": [288, 292, 298, 302], "installallus": 292, "instanc": [14, 21, 64, 75, 78, 82, 156, 162, 165, 166, 168, 178, 200, 292, 293, 295, 297, 298, 299], "instanti": [5, 7, 14, 21, 160, 171, 293, 297], "instead": [224, 233, 288, 289], "instruct": [14, 288, 298, 301], "int": [3, 4, 5, 6, 7, 8, 10, 11, 12, 17, 21, 22, 29, 30, 33, 37, 38, 46, 49, 55, 64, 66, 73, 75, 76, 77, 81, 83, 111, 115, 118, 123, 127, 135, 137, 140, 141, 148, 151, 152, 157, 160, 168, 177, 185, 186, 188, 192, 194, 196, 198, 205, 212, 217, 227, 266, 272, 277, 292, 298, 301], "int32": 216, "integ": [83, 205, 288], "integr": [293, 296], "intend": 35, "intenum": [125, 130, 231], "interact": [14, 38, 122, 132, 145, 156, 295], "interfac": [19, 23, 24, 39, 40, 41, 288, 293, 297], "intermitt": 289, "intern": [291, 298, 299], "internationalbrainlab": 292, "internet": [227, 245, 288, 292], "interpret": [171, 205, 221], "interrupt": 171, "interv": [4, 6, 8, 10, 12, 272], "intervent": 290, "intor": 217, "introduc": [5, 288, 290], "invalu": 289, "invers": 158, "invert": 288, "investig": [293, 296], "invok": [292, 293, 297], "involv": [293, 297], "io": [21, 49, 148, 160, 162, 165, 202, 205, 292], "iobas": [49, 148, 202, 205], "ip": [22, 227], "ipad": 289, "ipython": 292, "is_calibr": 240, "is_connect": [123, 160], "is_hd": 148, "is_main_fram": 70, "is_mock": 14, "is_run": 160, "is_toggl": 118, "isact": 81, "isloggedin": 75, "isnan": [8, 10], "issu": [152, 158, 224, 288, 290, 295, 298, 299], "item": [7, 182, 288, 292], "item_finish": 111, "item_result": 111, "item_start": 111, "itemtyp": 292, "iter": [151, 177, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 241], "iterate_protocol": 288, "iti": 7, "iti_reward": 7, "its": [28, 76, 81, 83, 208, 209, 237, 289, 290, 298, 300], "itself": [66, 75, 81, 83, 111, 115, 118, 290], "john": [298, 299], "json": [14, 171, 292], "jsonabl": [42, 171, 198], "jsonable_fil": [171, 198], "junk": 288, "just": [25, 298, 301], "keep": [14, 292], "kei": [11, 14, 17, 22, 31, 45, 60, 123, 160, 175, 177, 182, 228, 288, 292, 293, 294, 298, 300, 302], "kept": 155, "keyboard": [167, 292], "keypress": 167, "keyword": [75, 77, 78, 81, 82, 111, 160, 207, 228, 237, 245], "know": [293, 296], "ks022": [293, 296], "kwarg": [3, 5, 7, 9, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 25, 31, 38, 49, 54, 55, 60, 62, 67, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 111, 115, 123, 131, 132, 141, 142, 148, 149, 160, 177, 202, 205, 206, 207, 228, 232, 234, 237, 245, 260, 266, 273, 274, 277, 287, 293, 297], "l": 217, "lab": [152, 175, 195, 288, 292, 293, 294, 295, 298, 299, 300, 301], "label": [45, 186, 289, 290], "laboratori": [291, 298, 299], "lambda": 187, "languag": 291, "last": [28, 170, 177, 249, 295], "latenc": 290, "later": 288, "latest": [14, 31, 179, 238, 244, 290, 295], "latter": [227, 290, 292], "launch": [293, 297, 298, 299, 301], "layout": [173, 205, 288], "layout_templ": 173, "lazyloadcomplet": 66, "lazyloadstatu": 66, "le": [4, 6, 8, 10, 12, 185, 192, 272], "lead": [293, 297], "least": [289, 293, 294, 296], "leav": 290, "led": 288, "left": [3, 159, 216, 293, 294, 296, 297, 298, 302], "leftward": 5, "legend": 288, "length": [77, 152, 213], "less": [28, 288], "level": [7, 11, 14, 288, 292], "leverag": [293, 297], "lib": 217, "librari": 205, "lifetim": [293, 297], "light": [49, 289], "like": [160, 213, 292, 293, 297], "limit": 288, "line": [39, 40, 41, 42, 78, 167, 224, 288, 292, 293, 296, 297], "link": 70, "lint": 288, "liquid": 26, "list": [14, 21, 22, 33, 37, 38, 45, 60, 77, 111, 119, 144, 151, 152, 153, 156, 177, 185, 194, 198, 205, 240, 260, 288, 292, 293, 294, 298, 299], "listen": [160, 167], "listportinfo": [141, 207], "liter": [31, 49, 127, 151, 185, 193, 243], "live": 288, "ll": [298, 299], "load": [14, 21, 148, 163, 164, 175, 178, 179], "local": [37, 38, 39, 40, 41, 173, 177, 195, 233, 235, 237, 238, 244, 247, 250, 288, 292, 293, 295, 296, 297, 301, 302], "local_data_fold": 175, "local_fold": 235, "local_path": [37, 38, 175], "local_subjects_fold": 175, "local_subjects_path": 175, "locat": [21, 164, 235, 293, 297], "log": [7, 14, 73, 75, 78, 160, 162, 173, 178, 224, 243, 250, 251, 288, 293, 297], "log_level": [3, 5, 7, 11, 14], "log_result": 132, "loggedin": 75, "loggedout": 75, "logger": 14, "logic": [2, 13, 27, 293, 296, 297], "login": [75, 78, 88, 119, 298, 299], "loginfail": 75, "logout": [75, 119], "long": [5, 160, 289], "longer": [290, 292], "look": [21, 31, 177, 289, 293, 297], "loop": [159, 167, 293, 297], "loop_dur": 148, "loop_mod": 148, "loos": 289, "lost": 288, "low": 290, "lower": [28, 288], "lpt": 290, "lt": [4, 6, 8, 10, 12, 272], "m": [289, 292], "machin": [3, 7, 19, 23, 24, 123, 224, 288, 289, 290, 291], "made": [293, 297], "mai": [14, 173, 233, 289, 292, 295], "main": [4, 6, 8, 10, 12, 21, 70, 82, 83, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 230, 272, 289, 293, 294], "main_sync": [21, 161, 184, 232], "mainenlab": 175, "maintain": 81, "mainten": 288, "major": [249, 288, 295], "make": [3, 7, 14, 288, 289, 290, 291, 293, 295, 297, 298, 299, 301], "make_experiment_description_dict": 14, "manag": [75, 78, 243, 245, 249, 251, 252, 288, 290], "mandatori": [3, 298, 299], "mani": [293, 294], "manipul": [45, 151], "manner": [160, 292], "manual": [14, 289, 290, 295, 298, 299], "manufactur": 207, "map": [4, 6, 8, 10, 12, 21, 160, 163, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 293, 294], "map_tim": 16, "markdown": 73, "master": [161, 295], "match": [123, 126, 162, 165, 177, 207, 208, 209, 289, 293, 296], "math": [8, 10], "max": 217, "max_": [211, 293, 297], "max_envelope_sampl": 148, "max_length": 194, "max_samples_per_waveform": 148, "max_valu": 158, "maximum": [158, 177, 227, 293, 297], "maxlen": 194, "maxval": 51, "md": [247, 293, 295, 297], "mean": [7, 157, 292, 293, 295, 296, 297], "measur": 291, "meet": 207, "mention": [298, 299], "menu": [288, 289, 292, 293, 296], "merg": [14, 295, 298, 300], "mesoscop": [290, 293, 294], "mess": 22, "messag": [21, 35, 129, 159, 160, 221, 288], "metadata": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 293, 294], "method": [3, 7, 14, 15, 21, 24, 70, 75, 82, 160, 196, 205, 233, 247, 249, 251, 252, 288, 293, 297], "mice": 291, "micro": [45, 290], "microlit": 28, "micromet": 45, "microphon": [288, 293, 294], "microsoft": 292, "might": 289, "millilit": 28, "min": 217, "min_": [211, 293, 297], "min_length": 194, "min_valu": 158, "minimum": [28, 158], "minlen": 194, "minor": [249, 288, 295], "minut": 290, "minval": 51, "misc": [293, 297], "misconfigur": 290, "miss": [196, 288], "mix": 290, "mixin": [7, 13, 14, 21, 24, 293, 297], "mm": 290, "mock": [7, 14, 288], "modal": [293, 297], "mode": [31, 171, 203, 222, 223, 288, 292], "model": [4, 6, 8, 10, 12, 14, 76, 111, 170, 171, 178, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 200, 272, 289], "model2view": 118, "model_computed_field": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "model_config": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "model_field": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272], "modif": [293, 297], "modifi": [76, 81, 293, 297], "modul": [1, 2, 13, 52, 122, 123, 127, 181, 205, 254, 255, 258, 261, 264, 267, 270, 275, 278, 281, 285, 288, 293, 297], "modular": 288, "module_nam": 123, "molex": 289, "monitor": 77, "mono": 217, "more": [14, 21, 160, 176, 288, 290, 293, 296, 298, 299, 300, 301], "most": [160, 289, 293, 297], "mount": 289, "mous": [3, 11, 28, 279, 293, 296], "move": [11, 288], "ms2ul": 241, "multipl": [233, 288, 293, 297, 298, 302], "multithread": 82, "must": [14, 292, 293, 294, 298, 299, 302], "mutablemap": [182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195], "n": [37, 152, 157, 177, 221], "n_row": 196, "n_sampl": [49, 216], "n_trial": 28, "na": 196, "name": [4, 6, 8, 10, 12, 14, 21, 31, 46, 64, 66, 73, 75, 76, 81, 83, 111, 114, 115, 118, 119, 123, 132, 153, 160, 163, 165, 176, 177, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 200, 207, 227, 228, 230, 232, 233, 234, 272, 288, 293, 294, 296, 297, 298, 300, 302], "nan": [8, 10, 170, 196, 203], "narrow": [298, 299], "navig": [70, 298, 300, 301], "navigationtyp": 70, "nb": [159, 162, 298, 300], "ndarrai": [49, 148, 217, 241], "necessari": [238, 245, 289, 298, 299], "need": [7, 14, 17, 150, 216, 245, 288, 290, 292, 295, 298, 299, 300], "neg": 288, "neither": 289, "net": 21, "network": [21, 159, 163], "networksess": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "neuromodulatorchoicetrialdata": 273, "neuropixel": [159, 293, 294], "never": 257, "new": [64, 70, 75, 76, 81, 156, 157, 158, 233, 288, 292, 293, 295, 297], "new_block": [5, 274], "new_calibration_open_tim": 240, "new_count": 157, "new_sampl": 157, "new_subject_detail": 118, "newer": 288, "newest": 292, "next": [7, 11, 28, 176, 292, 295], "next_trial": [5, 7, 9, 11, 260, 266, 273, 274, 277], "nicknam": 14, "nidq": [293, 294], "nm": 288, "no_go": 3, "nois": [24, 217], "noise_index": 123, "non": [160, 222, 237, 288, 293, 296], "none": [3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 21, 25, 26, 31, 33, 37, 38, 42, 45, 49, 51, 54, 55, 62, 75, 76, 77, 81, 82, 111, 114, 115, 118, 119, 120, 123, 127, 129, 132, 135, 137, 140, 141, 142, 145, 148, 154, 155, 156, 160, 161, 162, 163, 164, 165, 167, 168, 170, 171, 173, 175, 178, 180, 184, 185, 186, 187, 188, 190, 191, 192, 193, 195, 196, 198, 203, 205, 207, 208, 209, 215, 216, 219, 222, 223, 224, 230, 232, 233, 234, 237, 243, 244, 245, 246, 248, 250, 251, 252, 272, 284], "nonetyp": [12, 184, 185, 186, 187, 188, 190, 191, 192, 193, 195], "nonewwindow": 292, "nor": 289, "norestart": 292, "normal": [66, 75, 81, 83, 111, 115, 118], "not_regist": 231, "not_set": [293, 296], "note": [14, 289, 298, 299, 300], "notebooks_extern": 292, "notepad": 292, "noth": [251, 279], "notic": [120, 288], "notif": 288, "notifi": [76, 81, 160], "notify_servic": 160, "notimplementederror": 126, "notion": 5, "notori": 289, "now": [288, 292, 293, 297], "np": 217, "nprobe": [46, 232], "npy": [293, 294], "nsampl": 217, "ntrial": [28, 170], "ntrials_correct": 170, "ntrials_engag": 170, "ntrials_nan": 170, "nullabl": 51, "num": 68, "number": [11, 14, 22, 37, 38, 46, 64, 76, 126, 152, 154, 160, 176, 177, 196, 205, 208, 209, 217, 249, 293, 294, 295], "number_of_expected_devic": [230, 233], "numpi": [170, 205, 216], "o": 216, "obj": [60, 118], "object": [4, 6, 7, 8, 10, 12, 17, 21, 26, 35, 38, 45, 55, 66, 75, 76, 81, 83, 111, 115, 118, 119, 160, 171, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 207, 250, 252, 272, 288], "obtain": [31, 202, 208, 225, 249, 250, 252], "occur": [83, 224, 243, 253, 289], "off": 289, "offer": [288, 289], "offici": 295, "offset": [198, 257, 288, 293, 297], "often": 292, "ok": 202, "old": [298, 300], "old_mean": 157, "old_std": 157, "older": [37, 38, 290, 292, 298, 300], "olivier_awesomechoiceworld": [293, 297], "omit": [298, 300], "omit_correct": 3, "omit_error": 3, "omit_feedback": [272, 273], "omit_no_go": 3, "on_error": 243, "on_item_finish": 111, "on_item_result": 111, "on_item_start": 111, "onboard": [127, 289], "onc": [14, 160, 202, 288, 298, 300], "one": [14, 21, 119, 160, 162, 165, 168, 176, 224, 233, 289, 290, 292, 293, 294, 296, 298, 300], "one_quickstart": 292, "onealyx": 168, "oneibl": 14, "ones": [14, 76, 81], "ongetanydeskresult": 62, "onli": [14, 21, 160, 162, 186, 202, 222, 223, 249, 251, 252, 279, 288, 289, 290, 293, 294, 295, 297], "onlin": [171, 288], "ons": [293, 297], "onto": 295, "open": [26, 70, 123, 205, 288, 289, 290, 292, 298, 299, 300, 301, 302], "open_time_": 123, "open_times_m": 241, "open_valv": 123, "oper": 126, "oplt": 171, "optic": [293, 294], "option": [3, 7, 14, 21, 26, 31, 38, 65, 66, 73, 75, 76, 77, 81, 83, 111, 115, 118, 123, 151, 152, 158, 160, 163, 167, 168, 175, 177, 178, 186, 187, 195, 217, 221, 222, 223, 224, 227, 233, 235, 237, 243, 245, 248, 288, 289, 292, 293, 294, 297, 298, 299, 300, 302], "optostim": 288, "order": [7, 14, 76, 293, 294, 298, 300], "ordereddict": 17, "org": [205, 292], "organiz": 150, "orient": 76, "origin": [249, 289, 290, 295], "osc": [16, 22], "osc_protocol": 22, "oscilloscop": 289, "other": [76, 81, 213, 233, 289, 290, 291, 292, 293, 294], "otherwis": [21, 35, 37, 38, 70, 75, 76, 81, 126, 158, 160, 162, 163, 164, 165, 175, 196, 220, 222, 223, 227, 233, 235], "our": [289, 290, 293, 295, 297], "out": [75, 150, 152, 160, 248, 288, 289, 292], "outfil": 292, "output": [14, 127, 175, 193, 217, 224, 234, 243, 288, 289, 290], "output_fil": 7, "outsid": 288, "over": [21, 28, 150, 177, 233, 289, 293, 296, 298, 300], "overal": [293, 296], "overflow": 288, "overload": [7, 66, 75, 81, 83, 111, 115, 118, 233, 257, 293, 297], "overrid": [14, 70], "overview": [293, 296, 298, 302], "overwrit": [233, 235], "overwritten": [173, 233, 288], "own": 150, "p": [22, 156], "p0": 274, "p00": 140, "p1": 274, "p2": 274, "p_i": 152, "p_idx": 152, "pack": 205, "packag": [288, 292, 298, 301], "page": [293, 296], "panda": [170, 171, 196, 198], "panel": [293, 296], "paper": 27, "param": [22, 45, 156, 163, 166, 175], "paramet": [3, 5, 7, 11, 14, 21, 26, 28, 29, 30, 31, 33, 35, 37, 38, 45, 46, 49, 54, 55, 62, 64, 66, 70, 73, 75, 76, 77, 78, 79, 81, 82, 110, 111, 112, 114, 115, 117, 118, 119, 120, 123, 126, 127, 129, 132, 145, 148, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170, 171, 173, 174, 175, 176, 177, 178, 179, 180, 189, 196, 198, 202, 203, 205, 207, 208, 209, 213, 216, 217, 221, 222, 223, 224, 225, 226, 227, 228, 233, 234, 235, 237, 238, 240, 241, 243, 245, 248, 249, 260, 266, 277, 284, 288, 292, 293, 297, 298, 302], "parent": [55, 66, 76, 114, 117, 120, 155, 156, 293, 294, 297], "parlanc": [293, 297], "pars": [111, 155, 156, 175, 250, 252, 288], "parser": [7, 14, 119, 155, 156, 260, 266, 277, 283, 287], "part": [293, 296], "partial": 233, "particip": [298, 299], "particular": [298, 300], "particularli": 290, "pass": [7, 14, 17, 31, 38, 77, 78, 81, 111, 130, 177, 222, 223, 237, 243, 288, 292, 293, 294, 296, 298, 302], "passiv": [3, 288, 292, 298, 299], "passivechoiceworld": [288, 293, 294], "passiveregisterraw": [293, 294], "passivetasktimelin": [293, 294], "password": [75, 117, 119, 292], "past": 288, "patch": [22, 249, 288, 295], "path": [5, 7, 14, 35, 37, 38, 42, 77, 119, 154, 163, 164, 170, 171, 173, 175, 176, 177, 178, 179, 180, 183, 187, 189, 195, 198, 216, 222, 223, 233, 235, 288, 292, 293, 296], "path_typ": [183, 187, 195], "pathlib": [35, 119, 163, 164, 233], "pathtyp": [183, 187, 195], "patient": 292, "pattern": [154, 235], "paus": [118, 288], "pause_dur": [4, 6, 8, 10, 12, 272], "pc": [21, 37, 38, 233, 289, 293, 296, 298, 300], "pd": 196, "pdf": [288, 295], "pdm": 288, "pend": [130, 160, 231, 233], "per": [170, 288, 289, 293, 294], "percent_correct": 170, "percent_error": 170, "percent_threshold": 77, "percentag": 77, "perform": [3, 11, 237, 238, 293, 297], "period": [257, 288, 293, 297], "person": 292, "pertin": [298, 299], "phase": [11, 22, 29, 30, 31, 32, 288], "phi": 45, "photometri": [293, 294], "piec": [7, 14, 289, 290], "pin": 288, "pip": [292, 298, 301], "pipe": 14, "pipelin": [14, 15, 290, 293, 294], "piplin": 14, "place": 289, "plai": [24, 127, 148, 217, 289], "plainseri": [183, 187], "plastic": 289, "platform": 167, "platformspecif": [49, 148, 202, 205], "platformspecificbas": [49, 148, 202, 205], "play_nois": [24, 125], "play_ton": [24, 125], "pleas": [292, 295, 298, 299], "pleft": 7, "plot": [171, 288], "plotwidget": 114, "plug": [289, 290], "pname": 45, "pnputil": 126, "point": [42, 73, 82, 173, 288, 290, 292, 293, 297], "pointer": [222, 223], "polar": 289, "polici": [292, 293, 297], "poor": 274, "popen": 222, "popul": [288, 298, 299], "popup": 50, "port": [22, 49, 115, 126, 135, 137, 140, 141, 142, 205, 207, 208, 209, 227, 288, 289, 290], "port_info": 141, "port_properti": [135, 140, 141], "portabl": 292, "posit": [4, 6, 7, 8, 10, 12, 22, 75, 78, 81, 82, 173, 213, 245, 272, 288], "position_set": [212, 260], "posixpath": [5, 7, 175], "possibl": [130, 233, 288, 289, 293, 294, 297, 298, 299], "post": 288, "post3": 295, "potenti": [158, 288, 290], "power": 289, "powershel": [288, 289, 298, 299], "pr": [288, 295], "pragma": [293, 297], "pre": [14, 210, 266, 288], "prealloc": 196, "preallocate_datafram": 196, "preced": [298, 299], "predic": [8, 10], "prefer": [173, 289], "prefix": 70, "pregener": 265, "prepar": [15, 111], "preprocess": 14, "prerequisit": 245, "presenc": [247, 295], "present": [233, 288], "press": [60, 221, 292, 298, 299], "pretti": 200, "pretty_nam": 200, "prevent": 289, "preview": 289, "previou": [11, 28, 31, 157, 288, 295], "previous_subject": 118, "print": 207, "prior": [14, 293, 297], "prob_typ": 213, "probability_left": 288, "probability_set": [170, 260], "probability_typ": 151, "probabl": [5, 151, 152, 260, 274], "probe": [46, 293, 294, 298, 301], "probe01a": 45, "probe01b": 45, "problem": [288, 290], "problemat": [293, 296], "proce": [75, 288], "procedur": [14, 119, 292, 298, 299], "procedures_nam": 156, "proceed": 38, "process": [132, 222, 223, 233, 292, 295], "produc": [171, 290], "product": 207, "program": [291, 292], "progress": [77, 83, 298, 299], "project": [14, 119, 288, 292, 297, 298, 299], "project_extract": [292, 293, 297], "projects_nam": 156, "prompt": [38, 50, 51, 221, 288, 292], "proper": [288, 290], "properli": [293, 296], "properti": [7, 11, 14, 21, 49, 55, 75, 76, 77, 81, 110, 112, 114, 118, 119, 123, 132, 135, 137, 140, 141, 142, 148, 160, 200, 202, 205, 230, 233, 240, 241, 260, 273], "proport": [3, 293, 296], "protocol": [2, 3, 5, 7, 9, 11, 14, 16, 20, 24, 26, 31, 162, 177, 257, 260, 263, 266, 269, 273, 274, 277, 279, 283, 287, 288, 291, 293, 294, 296, 297], "protocol_nam": [5, 9, 11, 14, 18, 257, 260, 266, 273, 277, 280, 287, 293, 297], "provid": [2, 7, 13, 17, 45, 73, 75, 82, 120, 150, 151, 168, 173, 175, 178, 205, 208, 209, 228, 235, 243, 245, 289, 293, 297, 298, 299], "prune": 292, "ps1": [289, 292, 298, 299, 300, 301, 302], "psychometr": 170, "pt": 288, "pull": [292, 295], "puls": [290, 293, 294], "pulse_valv": [115, 123], "pulse_valve_repeatedli": 123, "pupdat": 171, "pure": 170, "purpl": 219, "purpos": [3, 155, 291, 298, 299], "push": [148, 160, 295], "py": [156, 293, 295, 297, 298, 299, 300, 301, 302], "pybpod": 14, "pybpodapi": 123, "pydant": [4, 6, 8, 10, 12, 14, 111, 178, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 200, 272, 288], "pydantic_definit": [4, 6, 8, 10, 12, 272], "pyqt": 82, "pyqt5": [54, 55, 60, 62, 65, 66, 67, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 110, 111, 112, 115, 117, 118, 120], "pyqt_sign": [66, 75, 81, 83, 111, 115, 118], "pyqtproperti": [76, 81], "pyqtsign": [66, 75, 81, 83, 111, 115, 118], "pyrcc5": 84, "pyspin": [288, 292, 298, 302], "pytest": 295, "python": [14, 76, 81, 205, 291, 298, 299], "python310": 292, "pythongui": [70, 82], "pythonosc": 22, "pyuic5": 84, "q": 140, "qabstractbutton": 81, "qabstractitemdeleg": 65, "qabstractitemmodel": [76, 79], "qabstractitemview": 80, "qabstractscrollarea": 80, "qabstracttablemodel": 76, "qc": [186, 288, 298, 302], "qcolor": 55, "qcolorconst": 73, "qdialog": [54, 55, 60, 111, 115, 117, 120], "qframe": 80, "qlineedit": 78, "qlistview": 80, "qmainwindow": 118, "qml": [66, 75, 81, 83, 111, 115, 118], "qmodelindex": 76, "qobject": [54, 55, 60, 62, 65, 66, 67, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 83, 111, 115, 117, 118, 120], "qpaintdevic": [54, 55, 60, 62, 67, 71, 73, 77, 78, 80, 81, 111, 115, 117, 118, 120], "qprogressbar": 77, "qpushbutton": 81, "qrunnabl": 82, "qstandarditem": [110, 112], "qstandarditemmodel": 79, "qstyleditemdeleg": 65, "qt": [76, 81, 288], "qtcore": [54, 55, 60, 62, 65, 66, 67, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 111, 115, 117, 118, 120], "qtgui": [54, 55, 60, 62, 67, 71, 73, 77, 78, 79, 80, 81, 110, 111, 112, 115, 117, 118, 120], "qthread": 66, "qthreadpool": 82, "qtwebenginewidget": 70, "qtwidget": [54, 55, 60, 62, 65, 67, 71, 73, 77, 78, 80, 81, 111, 115, 117, 118, 120], "quadrat": 288, "quantifi": 3, "queri": [202, 205, 249], "query_lin": 202, "queu": 160, "queue": 160, "quiescenc": [257, 288, 293, 297], "quiescent": 257, "quiescent_period": [4, 6, 7, 8, 10, 12, 272], "quiet": [253, 292], "quit": 292, "qurl": 70, "qvariant": 76, "qwebenginepag": 70, "qwebengineview": 70, "qwidget": [54, 55, 60, 62, 67, 71, 73, 77, 78, 80, 81, 111, 115, 117, 118, 120], "r": [22, 179, 217], "r0": 274, "r1": 274, "r2": 274, "race": 288, "rais": [21, 31, 35, 126, 151, 152, 160, 162, 173, 178, 196, 207, 222, 223, 224, 230, 232, 233, 234, 237, 243, 245, 288], "raise_except": 238, "raise_fail_as_except": 132, "raise_on_except": 21, "raise_on_fail": 49, "random": [158, 217, 293, 297], "rang": [152, 158], "rate": [16, 127, 158, 186, 217, 289, 298, 302], "rather": 196, "raw": [42, 176], "raw_behavior_data": [293, 294], "raw_ephys_data": [293, 294, 298, 300], "raw_imaging_data": [176, 293, 294], "raw_imaging_data_00": 176, "raw_imaging_data_01": 176, "raw_sess": [298, 300], "raw_sync_data": [293, 294], "raw_task_data": 176, "raw_task_data_00": [14, 176, 293, 294, 298, 300], "raw_task_data_01": [293, 294], "raw_video_data": [234, 293, 294], "rawiobas": [49, 148, 202, 205], "rca": 290, "re": [21, 22, 288, 289], "reach": [292, 293, 297], "read": [167, 175, 198, 202, 205, 247, 288, 293, 297, 298, 300], "read_task_parameter_fil": 14, "readi": [11, 24], "readm": [293, 297], "realiz": [293, 297], "reason": 290, "reboot": 289, "recalibr": 289, "receiv": [21, 28, 160, 205, 289], "recheck": 227, "recogn": [73, 178], "recommend": [292, 298, 302], "record": [14, 46, 171, 187, 279, 289, 293, 294, 297, 302], "recurs": [158, 233], "red": [77, 219], "redefin": 289, "ref_shank": 45, "refer": [7, 14, 17, 21, 288, 295], "reference_developer_guid": 293, "reformat": 295, "refresh_r": 160, "regard": [289, 293, 296], "regardless": [293, 296], "regex": 288, "regexp": 126, "regist": [14, 123, 195, 288], "register_sess": 14, "register_softcod": 123, "register_to_alyx": 14, "registr": [14, 293, 296], "regress": 288, "regular": [123, 126, 207], "rel": [45, 152], "rel_extent_i": 55, "rel_extent_x": 55, "rel_pos_i": 55, "rel_pos_x": 55, "relat": [13, 27, 237, 293, 297], "relationship": [293, 294], "releas": [288, 292], "relev": [295, 298, 300], "reli": [247, 290], "reliabl": 288, "remain": [152, 289, 298, 300], "rememb": [117, 288], "remot": [21, 37, 38, 160, 162, 163, 164, 166, 168, 177, 195, 230, 232, 233, 234, 235, 237, 238, 244, 247, 251, 252, 288, 292, 298, 300, 301, 302], "remote_data_fold": [163, 175], "remote_devic": 118, "remote_devices_fil": 163, "remote_experiment_description_stub": 233, "remote_fold": 235, "remote_path": [37, 38, 175], "remote_rig": [21, 159], "remote_session_path": 233, "remote_subjects_fold": [175, 233], "remote_subjects_path": 175, "remotesign": 292, "remov": [37, 38, 257, 288, 293, 297, 298, 300], "repair": 288, "repetit": 123, "replac": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 290, 293, 297], "replug": 289, "repo": 150, "report": [21, 83, 292, 295], "reposit": 289, "repositori": [150, 237, 238, 247, 252, 253, 288, 293, 295, 297], "repres": [35, 75, 244, 250, 252], "reproduc": 291, "request": [70, 159, 160, 295], "requir": [4, 6, 8, 10, 12, 14, 21, 28, 76, 81, 126, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 272, 289, 292, 293, 295, 297, 298, 302], "reset": [76, 81, 237], "reset_repo": 237, "resizemod": 64, "resolut": [298, 302], "resolv": [162, 289], "respect": [288, 289, 290, 298, 300], "respond": 221, "respons": [3, 21, 159, 160, 170, 221, 289], "response_receiv": 160, "response_sid": [4, 6, 8, 10, 12, 272], "response_tim": [4, 6, 8, 10, 12, 272], "rest": 152, "restart": [126, 289], "restrict": [288, 292], "restructur": 288, "result": [14, 60, 62, 82, 83, 111, 132, 145, 227, 237, 257, 290, 292, 293, 297, 298, 299], "retranslateui": [86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108], "retriev": [7, 14, 21, 208, 209, 224, 247, 249, 252, 292], "return": [3, 7, 11, 14, 17, 21, 22, 24, 26, 28, 29, 30, 31, 33, 35, 37, 38, 42, 45, 49, 54, 62, 70, 75, 76, 82, 111, 115, 118, 119, 120, 123, 126, 127, 129, 132, 144, 145, 148, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 168, 170, 171, 173, 175, 176, 177, 178, 179, 180, 196, 198, 200, 202, 203, 205, 207, 208, 209, 212, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 233, 234, 235, 237, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 257, 260, 266, 277, 283, 284, 287, 288, 292, 293, 296, 297], "return_typ": [183, 187], "revers": [22, 288], "revert": 288, "review": 38, "revis": [66, 75, 76, 81, 83, 111, 115, 118], "reward": [3, 7, 11, 26, 28, 31, 274, 288], "reward_amount": [4, 6, 8, 10, 12, 260, 272], "reward_amount_ul": 26, "reward_set_ul": 260, "reward_tim": 7, "reward_valve_tim": [4, 6, 8, 10, 12, 26, 272], "reward_volume_ul": 28, "rework": 288, "rewritng": [293, 297], "ribbon": 289, "rich": 274, "rig": [15, 21, 38, 159, 160, 288, 289, 290, 291, 293, 296, 297], "rig_nam": 184, "rig_set": [111, 112], "rig_vers": 161, "right": [3, 159, 216, 289, 292, 293, 294, 296, 298, 302], "rigset": [14, 79, 111, 112, 118, 132, 145, 178, 226], "rigwizard": 117, "rise": [217, 290], "rj45": 290, "robust": [288, 290], "role": 76, "roll": 45, "rollback": [288, 290], "root": [233, 293, 297], "rotari": [23, 288, 293, 297], "rotary_encod": 123, "rotary_encoder_bpod_port": 185, "rotaryencodermixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "routin": [288, 289], "row": [76, 196], "rowcount": 76, "rst": [293, 295], "rsync": [298, 300], "ruff": [288, 295], "run": [7, 14, 17, 21, 25, 38, 66, 82, 111, 132, 156, 160, 171, 233, 245, 288, 289, 294, 297, 300, 302], "run_passive_visual_stim": 16, "run_subprocess": 111, "runner": [5, 7], "runtimeerror": [160, 243, 245], "sa_tim": 16, "safe": [249, 295], "same": [14, 76, 81, 162, 196, 198, 233, 265, 293, 294, 298, 299], "sampl": [49, 127, 157, 217], "sample_r": 215, "sampler": 127, "sampling_rate_hz": 148, "sanwork": [290, 291], "sata": 289, "save": [14, 115, 166, 183, 217, 265, 289, 293, 297, 298, 300], "save_task_parameters_to_json_fil": 14, "save_trial_data_to_json": 14, "scale": [115, 158, 288], "scale_initi": 115, "scale_stable_chang": 115, "scale_text_chang": 115, "scenario": [274, 289], "scrambl": 288, "screen": 288, "screen_freq_target": 192, "screen_freq_test_d": 192, "screen_freq_test_statu": 192, "screen_index": 55, "screen_lux_d": 192, "screen_lux_valu": 192, "screenshot": [298, 299], "screwdriv": 290, "script": [245, 288, 289, 292, 299, 301, 302], "scriptabl": [76, 81], "sdk": [288, 292], "seamless": 292, "search": [177, 292], "seat": 289, "sec": [257, 293, 297], "second": [26, 123, 227, 288, 289, 292], "section": [76, 290, 292, 293, 294, 298, 300], "sectionwidth": 64, "secur": [289, 292], "see": [7, 22, 152, 205, 289, 292, 293, 296, 298, 300], "seem": 290, "select": [21, 288, 292, 293, 295, 296, 298, 299], "self": [14, 17, 21, 26, 159, 293, 297], "semant": 295, "send": [16, 21, 159, 160, 216, 289], "send2bonsai": 22, "send_spac": 17, "send_trial_info_to_bonsai": [7, 16], "sensit": 221, "sensor": [288, 289], "sent": [160, 166, 168, 205, 216], "separ": [14, 82, 155, 224, 288, 295, 298, 300, 302], "sequenc": [21, 66, 75, 81, 83, 111, 115, 118, 155, 156, 241, 293, 296, 297, 298, 299], "serial": [49, 126, 148, 202, 205, 207, 208, 209, 288, 290], "serial1": 185, "serial2": 185, "serial3": 185, "serial4": 185, "serial5": 185, "serial_numb": [205, 208], "serial_queri": [135, 137, 140, 141], "serial_singleton": [49, 148, 202], "serialbas": [49, 148, 202, 205], "serialize_path": 189, "serialposix": [49, 148, 202, 205], "serialsingleton": [49, 148, 202, 288], "serialutil": [49, 148, 202, 205], "serv": [298, 299], "server": [38, 39, 40, 41, 227, 230, 232, 233, 234, 288, 292, 293, 294, 297, 298, 300, 301, 302], "server_uri": 165, "servic": [21, 159, 160], "service_uri": 165, "sess": [293, 297], "session": [5, 11, 14, 21, 28, 31, 37, 38, 119, 154, 156, 171, 176, 177, 198, 210, 233, 274, 288, 289, 290, 297, 298, 299, 300], "session_fold": 119, "session_info": [31, 118], "session_path": [31, 176, 177, 233], "session_template_id": [266, 277], "sessioncopi": [38, 230, 232, 234, 288], "set": [7, 14, 28, 73, 76, 78, 81, 84, 151, 160, 163, 164, 171, 173, 175, 177, 178, 179, 200, 225, 227, 240, 243, 288, 289, 290, 291, 293, 294, 297, 299, 300, 301], "set_status_l": 123, "set_threshold": 49, "setact": 81, "setdata": 76, "setdatafram": 76, "setfonts": 73, "setlogcolor": 73, "settings_fil": [170, 171], "setup": [46, 187, 288, 292], "setupui": [86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108], "sever": 290, "shank": 45, "shank_spacings_um": 45, "shape": [216, 217, 289], "share": [228, 298, 299], "shell": 292, "short": 248, "shorter": 289, "should": [4, 6, 8, 10, 12, 14, 21, 73, 127, 150, 158, 160, 162, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 207, 272, 289, 290, 292, 293, 296, 297, 298, 302], "show": [120, 288, 289, 290, 298, 301, 302], "show_trial_log": [3, 5, 7, 11, 288], "showev": 67, "shown": [298, 299], "side": [3, 22, 260, 274, 288, 295], "sig": 289, "sigint": [14, 293, 297], "sigma": 22, "sign": [170, 292], "signal": [66, 75, 76, 78, 81, 82, 83, 111, 115, 118, 289, 290], "signatur": 292, "signed_contrast": [12, 288], "silenc": 243, "silent": [31, 224], "sim_freq": 22, "simplepdf": 295, "simpleudpcli": 22, "simplewrapp": [54, 55, 60, 62, 65, 66, 67, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 110, 111, 112, 115, 117, 118, 120], "simpli": [298, 302], "simul": 7, "simulu": 3, "sinc": [249, 290], "singl": [129, 159, 216, 230, 289], "singleton": 288, "sip": [54, 55, 60, 62, 65, 66, 67, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 110, 111, 112, 115, 117, 118, 120], "situat": 289, "size": [73, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195], "skew_zero": 151, "skip": [130, 288, 298, 300], "skip_event_replai": 277, "skip_initi": 123, "slack": [298, 299], "slip": 289, "small": 288, "snappi": 292, "snapshot": [233, 288], "so": [233, 274, 295, 298, 299], "softcod": [17, 22, 123], "softcode_dict": 123, "softcode_dictionari": 17, "softwar": [238, 244, 252, 293, 294, 298, 301, 302], "sole": 14, "solut": 129, "some": [160, 292, 293, 296, 297], "somewher": 21, "sort": 76, "sortord": 76, "sound": [24, 127, 290, 293, 297], "sound_board_bpod_port": 185, "sound_card": 123, "sound_play_nois": 24, "sound_play_ton": 24, "soundcard": [217, 289, 290], "sounddevic": [127, 217], "soundmixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "sourc": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 40, 41, 42, 45, 46, 47, 49, 51, 54, 55, 57, 58, 60, 62, 64, 65, 66, 67, 68, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 111, 112, 114, 115, 117, 118, 119, 120, 121, 123, 124, 126, 127, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 148, 149, 151, 152, 153, 154, 155, 156, 157, 158, 160, 161, 162, 163, 164, 165, 166, 167, 168, 170, 171, 173, 174, 175, 176, 177, 178, 179, 180, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 200, 202, 203, 205, 206, 207, 208, 209, 211, 212, 213, 215, 216, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 230, 231, 232, 233, 234, 235, 237, 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 257, 260, 263, 266, 269, 272, 273, 274, 277, 280, 283, 284, 287, 288, 292, 295, 298, 300], "space": [45, 77, 224], "speaker": 216, "spec_vers": 161, "specif": [70, 170, 173, 235, 288, 289, 290, 293, 294, 297], "specifi": [14, 66, 75, 76, 77, 81, 83, 111, 115, 118, 123, 126, 151, 158, 178, 196, 205, 207, 222, 223, 227, 228, 243, 293, 294, 298, 300], "sphinx": 295, "spikeglx": [293, 294], "spinnak": [288, 292, 298, 302], "splash": 90, "split": 288, "spontan": [25, 279], "spontaneoussess": 280, "stabil": 202, "stabl": [202, 203], "stagger": 274, "standard": [76, 81, 157, 159, 161, 167, 178, 290, 291], "start": [7, 14, 15, 21, 24, 70, 111, 159, 173, 198, 222, 223, 288, 289, 290, 292, 293, 297, 300], "start_ephys_sess": [298, 301], "start_hardwar": [7, 14, 18, 25, 277], "start_mixin_bonsai_camera": 15, "start_mixin_bonsai_microphon": 15, "start_mixin_bonsai_visual_stimulu": 16, "start_mixin_bpod": 17, "start_mixin_frame2ttl": 19, "start_mixin_network": 21, "start_mixin_rotary_encod": 23, "start_mixin_sound": 24, "start_mixin_valv": 26, "start_next_calibr": 115, "start_stop": 118, "start_video_sess": [298, 302], "state": [3, 7, 19, 23, 24, 78, 81, 123, 233, 237, 288, 290, 291, 298, 300], "state_nam": 24, "state_tim": 24, "statebutton": 81, "statechang": 81, "static": [7, 14, 17, 64, 123, 160, 171, 205, 228, 234, 257, 260, 266, 277, 283, 287], "statu": [75, 78, 110, 111, 112, 129, 159, 233, 249, 288, 298, 300], "status_item": 111, "statuschang": 75, "statusitem": 111, "step": [7, 288, 289, 290, 291, 292, 293, 297], "stereo": [216, 217], "stick": 289, "still": [233, 292, 298, 299], "stim": [5, 22, 210], "stim_angl": [4, 6, 8, 10, 12, 22, 272], "stim_freq": [4, 6, 8, 10, 12, 22, 272], "stim_gain": [4, 6, 8, 10, 12, 22, 31, 260, 272], "stim_gain_on_error": 31, "stim_phas": [4, 6, 8, 10, 12, 22, 272], "stim_probability_left": [4, 6, 8, 10, 12, 212, 272], "stim_revers": [4, 6, 8, 10, 12, 260, 272, 288], "stim_sigma": [4, 6, 8, 10, 12, 22, 272], "stimul": [3, 293, 294], "stimuli": [290, 291], "stimulu": [3, 22, 31, 288], "stock": [298, 299], "stop": [25, 148, 160, 289], "stop_and_clos": 60, "stop_ev": 160, "stop_mixin_bonsai_record": 15, "stop_mixin_bonsai_visual_stimulu": 16, "stop_mixin_bpod": 17, "stop_mixin_network": 21, "stop_sound": 125, "stopiter": 224, "store": [76, 81, 173, 195, 288, 293, 294], "store_tru": 156, "str": [3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 21, 31, 35, 37, 38, 45, 46, 49, 62, 64, 66, 73, 75, 81, 83, 111, 114, 115, 117, 118, 119, 120, 123, 126, 129, 132, 135, 140, 141, 142, 153, 154, 156, 160, 161, 163, 165, 166, 167, 168, 171, 174, 175, 176, 177, 178, 179, 180, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 200, 202, 203, 205, 207, 208, 209, 213, 216, 217, 221, 222, 223, 224, 226, 227, 230, 232, 233, 234, 243, 244, 246, 247, 248, 249, 272, 284], "str_must_not_contain_spac": 195, "straightforward": 290, "stream": [25, 49, 279, 293, 296], "streo": 217, "strike": 292, "string": [14, 21, 35, 50, 66, 75, 76, 81, 83, 111, 115, 118, 205, 207, 224, 243, 244, 249, 250, 284, 288, 295], "struct": 205, "structur": [25, 161, 274, 293, 297], "stub": [14, 230, 232, 233, 234, 298, 300], "style": 295, "sub": [293, 294], "subclass": [3, 21], "subfold": [298, 300], "subject": [14, 21, 31, 37, 38, 46, 119, 175, 176, 177, 195, 288, 290, 293, 296, 298, 299, 300, 301, 302], "subject_nam": [31, 46, 156, 177], "subject_weight_g": 28, "subject_weight_gram": 14, "submit": 292, "subprocess": [111, 222, 223, 224, 237, 288], "subprocesserror": 243, "subsequ": [14, 298, 299], "subtract": 7, "success": [75, 224, 235, 298, 300], "successfulli": [14, 83, 126, 160, 168, 233, 252], "suffici": 289, "suffix": [68, 173, 176], "suggest": [298, 299], "super": [7, 21, 293, 297], "suppli": 289, "support": [205, 288, 290, 293, 294, 295], "suppress": [224, 243], "sure": [7, 14, 288, 289, 290, 293, 297, 298, 301], "swap": 289, "swiftli": [298, 299], "switch": [288, 289], "sync": [21, 186, 230, 295], "sync_label": [186, 293, 294], "synchron": [160, 290], "synchronis": [293, 294], "sysdefault": [127, 193, 289], "system": [111, 126, 289, 292], "systemat": [298, 300], "t": [14, 22, 25, 178, 180, 225, 233, 288, 289, 292, 298, 300], "tab": [288, 289], "tababout": 92, "tabdata": [66, 94], "tabdoc": 96, "tabl": [3, 7, 11, 198, 295], "tablog": 98, "tabsess": 100, "tag": [37, 38, 230, 232, 233, 234, 249, 251, 252, 288, 292, 295, 298, 300, 301, 302], "take": [7, 35, 249, 290, 292, 293, 296], "talk": [293, 297], "tape": 289, "tare": [115, 202], "target": 288, "task": [2, 5, 7, 11, 13, 14, 17, 25, 27, 83, 119, 155, 156, 159, 170, 171, 176, 198, 288, 289, 291, 292, 300], "task_collect": 14, "task_fil": 119, "task_nam": [31, 119, 177], "task_param": 26, "task_paramet": [14, 118, 293, 297], "task_parameter_fil": 14, "task_protocol": 14, "task_qc": [293, 296], "task_set": [31, 170, 177], "taskpc": [298, 300], "taskqc": [293, 296], "tcp": 159, "tdm": [293, 294], "team": [289, 298, 299], "temp": 292, "templat": [173, 266, 292], "temporari": 292, "temporarili": 288, "termin": [160, 298, 299, 300, 301, 302], "test": [7, 155, 288, 289, 293, 296], "test_olivier_awesomechoiceworld": [293, 297], "test_subject": 119, "test_subject_nam": 119, "texp": [257, 293, 297], "text": [73, 78, 167, 219, 290, 292], "th": 152, "than": [28, 37, 38, 158, 196, 288, 290, 292, 298, 300], "thei": [251, 293, 296, 297], "them": [14, 160, 224, 290, 292], "therefor": [14, 293, 294], "theta": 45, "thi": [3, 4, 6, 7, 8, 10, 11, 12, 13, 14, 17, 21, 35, 37, 38, 45, 70, 75, 78, 82, 120, 150, 155, 158, 160, 167, 173, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 205, 221, 227, 228, 230, 232, 233, 234, 235, 237, 238, 243, 244, 245, 247, 249, 250, 251, 252, 257, 272, 274, 288, 289, 290, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302], "third": 295, "those": [21, 76, 81, 196, 293, 297], "thread": [21, 82, 83, 111, 160, 288], "three": [295, 298, 300], "threshold": 77, "threshold_dark": 49, "threshold_light": 49, "through": [7, 31, 243, 245, 249, 251, 252, 288, 289, 293, 297, 298, 299, 300], "throughout": 150, "throw": 288, "tie": 289, "tightli": 289, "time": [7, 14, 17, 21, 26, 150, 160, 170, 198, 217, 227, 288, 290, 293, 296], "time_elaps": [14, 170], "time_m": 241, "timelin": [37, 38, 170, 288, 293, 294], "timeout": [21, 227], "timeseri": [293, 294], "timestamp": [160, 293, 294], "titi": 156, "titl": [51, 184, 186, 187, 195], "to_byt": 205, "to_dict": 161, "todo": 257, "togeth": 13, "toggl": [298, 299], "toggle_status_l": 118, "toggle_valv": [115, 123], "token": [21, 75, 166, 168], "tone": [24, 217], "tool": [288, 289], "total": 14, "toto": 156, "traceback": 83, "track": [14, 289], "train": [11, 31, 288, 290, 291, 298, 302], "training_info": [11, 31, 118], "training_level": 287, "training_phas": [11, 12, 31], "trainingchoiceworld": [3, 260, 288], "trainingchoiceworldsess": [283, 287], "trainingchoiceworldtrialdata": 11, "trainingcw": 288, "trainingphasechoiceworld": 288, "trainingrig_savevideo_trainingtask": [289, 298, 302], "trainingstatu": [293, 294], "tranfer_data": [298, 300], "transfer": [37, 38, 39, 40, 41, 175, 233, 288, 289, 293, 297, 298, 300, 301, 302], "transfer_data": [288, 298, 300, 301, 302], "transit": [22, 288], "translat": 27, "tri": 13, "trial": [3, 4, 5, 6, 7, 8, 10, 11, 12, 14, 16, 22, 24, 25, 28, 170, 171, 196, 198, 213, 265, 266, 288, 293, 296, 297], "trial_complet": [3, 7], "trial_correct": [4, 6, 8, 10, 12, 272], "trial_data": [170, 171], "trial_num": [4, 6, 8, 10, 12, 22, 272], "trial_tabl": 14, "trialdatadefinit": 14, "trialdatamodel": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 272, 273], "trialregisterraw": [293, 294, 297], "trials_tabl": [198, 288], "tricki": 17, "trigger": [15, 288, 293, 295, 297], "trigger_bonsai_camera": 15, "trigger_camera": 125, "trivial": [293, 297], "true": [4, 6, 7, 8, 10, 12, 14, 21, 37, 38, 70, 75, 76, 77, 81, 123, 126, 132, 160, 162, 165, 166, 168, 178, 184, 185, 186, 187, 188, 189, 190, 192, 193, 194, 195, 202, 205, 220, 221, 222, 223, 224, 227, 232, 233, 234, 235, 237, 243, 248, 253, 272, 287], "truncat": [158, 257, 293, 297], "trust": 292, "try": [233, 289], "ttl": [19, 217, 288, 289, 290, 293, 294], "ttyusb0": 205, "tupl": [31, 49, 75, 77, 78, 81, 82, 83, 135, 137, 140, 141, 157, 168, 198, 202, 205, 233, 244], "turn": 3, "tutori": 82, "two": [244, 292, 293, 294, 298, 299], "type": [3, 5, 7, 9, 11, 14, 17, 20, 21, 22, 24, 26, 29, 30, 31, 33, 35, 37, 38, 49, 54, 62, 66, 70, 75, 76, 81, 82, 83, 111, 112, 115, 118, 119, 120, 123, 126, 129, 132, 144, 145, 148, 151, 152, 153, 154, 156, 157, 158, 160, 161, 162, 163, 164, 166, 168, 170, 171, 173, 175, 176, 177, 178, 179, 180, 194, 196, 198, 200, 202, 203, 205, 207, 208, 209, 212, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 230, 232, 233, 234, 235, 237, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 257, 260, 263, 266, 269, 273, 274, 277, 283, 284, 287, 288, 292, 298, 299, 300, 301, 302], "typeerror": 178, "typic": [158, 293, 297], "u": [196, 289, 293, 297], "udp": [16, 22, 159, 160, 163, 288], "udp_client": 22, "udpclient": 22, "ui": 288, "ui_frame2ttl": 54, "ui_login": 117, "ui_splash": 60, "ui_tab_about": 62, "ui_tab_data": 67, "ui_tab_doc": 71, "ui_tab_log": 73, "ui_tababout": 62, "ui_tabdata": 67, "ui_tabdoc": 71, "ui_tablog": 73, "ui_upd": 120, "ui_valid": 111, "ui_valv": 115, "ui_wizard": 118, "ul": [28, 31], "ul2m": 241, "unabl": [230, 232, 233, 234], "unclear": 17, "uncommit": [253, 295], "under": [288, 298, 300], "underlin": 219, "underscor": [293, 297], "unexpect": 288, "unfil": 288, "unfold": [293, 297], "unicod": 288, "unicodedecodeerror": 224, "uniform": [151, 213, 217], "union": [12, 184, 185, 186, 187, 188, 190, 191, 192, 193, 195, 244, 250, 252], "uniqu": [293, 294], "unit": [155, 203, 288, 289], "unittest": 292, "unlik": [21, 233, 293, 296], "unnecessari": 288, "uno": 207, "unobtrus": 292, "unpack": 205, "unplug": [289, 290], "unreli": 288, "unscrew": 290, "unsupport": 151, "until": [25, 36, 158], "unus": [14, 160, 168, 288], "unvers": 295, "up": [21, 78, 84, 160, 288, 289, 290, 291], "upcom": 171, "updat": [3, 7, 14, 21, 66, 77, 79, 102, 114, 120, 157, 162, 168, 171, 179, 227, 233, 244, 288, 290, 295], "update_avail": 120, "update_data": 77, "update_graph": 171, "update_titl": 171, "update_tri": [170, 171], "upgrad": [237, 245, 288, 292], "upload": 217, "upon": [183, 293, 295, 297, 298, 299, 300], "upper": 288, "uri": [21, 160, 162, 163, 165, 292], "url": [70, 75, 129, 166, 168, 195, 288, 292, 298, 299], "url_doc": 70, "us": [7, 13, 14, 21, 22, 24, 25, 35, 46, 66, 75, 76, 78, 81, 82, 83, 111, 115, 118, 120, 122, 123, 126, 127, 150, 151, 156, 159, 160, 163, 167, 171, 175, 177, 178, 195, 196, 205, 207, 217, 224, 227, 252, 253, 260, 279, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 299, 300, 301, 302], "usabl": [288, 292, 298, 299], "usag": [42, 77], "usb": [208, 209, 289, 290], "usb2": 289, "usb3": 289, "use_scal": 115, "user": [14, 25, 36, 38, 75, 76, 78, 81, 119, 166, 167, 173, 200, 208, 221, 238, 288, 289], "usernam": [75, 78, 117, 119, 166, 195, 292, 298, 299], "userprofil": 292, "usual": [288, 289, 292], "utf": 205, "util": [298, 299], "v": [187, 195, 292], "v1": [4, 6, 8, 10, 12, 182, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 272, 288], "v7": [288, 295], "v8": [295, 299], "v_basic": 249, "valid": [14, 60, 73, 104, 129, 130, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 178, 183, 200, 288, 289, 290], "valid_path": 187, "validate_assign": 195, "validate_iblrig": 289, "validate_remote_data_path": 195, "validate_video": 288, "validation_result": 60, "validationerror": [178, 196], "validator_item": 111, "validatoritem": 111, "validatorseri": [135, 137, 140, 142], "valu": [11, 17, 31, 76, 81, 83, 114, 115, 123, 125, 130, 151, 152, 157, 158, 159, 175, 182, 196, 205, 207, 228, 231, 237, 247, 288, 289, 292, 293, 296, 298, 299], "valueerror": [31, 151, 152, 207], "valv": [26, 36, 106, 123, 288], "valve1": 123, "valve_id": 123, "valve_numb": 123, "valve_open": 26, "valvemixin": [3, 5, 7, 9, 11, 257, 260, 263, 266, 269, 273, 274, 277, 283, 287], "valvevalu": 114, "variabl": [7, 21, 77, 156, 158, 160, 228, 295], "variant": [293, 297], "variat": 289, "variou": [7, 14, 170, 207, 288, 295], "vc_redist": 292, "vcredist_x64": 292, "ve": 290, "vector": 216, "venv": [289, 292, 298, 299, 300, 301, 302], "verbos": 288, "veri": [293, 294], "verifi": [245, 289, 290, 293, 296, 298, 300], "version": [14, 120, 179, 184, 238, 244, 249, 250, 252, 288, 289, 290], "version_manag": 288, "via": [16, 217, 289, 290], "vid": [135, 140], "video": [37, 38, 41, 234, 288, 289, 300], "view": [7, 170, 288, 298, 300], "viewephi": [298, 301], "virtual": [245, 292, 295], "visibl": [173, 293, 297], "visual": [22, 288, 291, 298, 301], "visualis": [293, 296], "voil\u00e0": [293, 297], "voltag": 289, "volum": [26, 28, 31, 288, 290], "volume_ul": 241, "volumes_ul": 241, "vsu_4": 292, "wa": [31, 35, 75, 166, 168, 208, 290, 293, 294, 298, 300], "wai": [17, 167, 288, 290], "wait": [21, 160, 222, 223, 227, 288, 292, 295], "want": [17, 208, 209, 293, 297, 298, 299], "warn": [130, 162, 288, 290, 293, 296], "watch": 171, "water": [14, 28, 170, 288, 293, 297], "water_calibration_d": 194, "water_calibration_n": 194, "water_calibration_open_tim": 194, "water_calibration_rang": 194, "water_calibration_weight_perdrop": 194, "water_deliv": 170, "we": [7, 17, 196, 257, 274, 289, 290, 293, 295, 297, 298, 299], "weak": 290, "web": 70, "webclient": [119, 168], "webpag": [293, 296], "webrequest": 292, "websit": 295, "week": [37, 38, 298, 300], "weight": [14, 28, 202, 203, 288], "weights_g": 241, "welcom": 291, "well": 290, "were": [38, 288], "wet": 295, "what": [293, 297], "wheel": [3, 288, 292], "when": [7, 14, 17, 21, 75, 81, 83, 160, 162, 175, 205, 207, 221, 243, 288, 289, 293, 296, 297, 298, 299, 302], "when_us": [183, 187], "where": [3, 5, 17, 76, 176, 228, 288], "whether": [22, 70, 75, 243, 244, 245, 248, 293, 296], "which": [21, 77, 151, 160, 173, 196, 209, 233, 292, 293, 294, 295, 296, 297, 298, 299, 302], "while": [81, 224, 290, 292], "whilst": 31, "white": [73, 217, 219, 289], "whole": [233, 293, 297], "wht": 289, "why": [293, 296], "widefield": [293, 294], "widget": [73, 77, 78, 120], "width": [55, 186, 293, 294, 298, 302], "window": [70, 126, 173, 217, 289, 290, 291, 298, 299], "windowspath": 288, "wire": [186, 289, 290], "wish": [298, 301], "within": [21, 158, 222, 223, 245, 293, 296, 297, 298, 302], "without": [75, 150, 159, 176, 221, 288, 289, 292, 293, 295, 296, 298, 299, 300], "wizard": [14, 108, 288, 298, 299], "won": [289, 298, 300], "work": [5, 7, 249, 251, 252, 253, 288, 289, 290, 292, 295, 298, 299], "worker": [83, 111, 288], "workersign": 82, "workflow": [173, 187, 222, 223, 288, 289, 302], "workflow_fil": [173, 222, 223], "world": [2, 5, 11, 27, 170, 260, 265, 288], "worth": 170, "wrap": [17, 160], "wrapper": [54, 55, 60, 62, 65, 66, 67, 70, 71, 73, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 110, 111, 112, 115, 117, 118, 120], "writabl": [76, 81], "write": [205, 230, 232, 233, 234, 295, 296], "write_pack": 205, "written": 205, "wrong": [162, 288], "www": [70, 82, 292], "x": 45, "x01": 140, "x1b": 219, "x64": 292, "xda": 137, "xml": 173, "xonar": [127, 193, 289], "y": [45, 175, 221, 288], "yaml": [5, 7, 14, 21, 37, 38, 111, 159, 162, 164, 177, 178, 184, 195, 233, 234, 288, 289, 290, 292, 293, 294, 297, 298, 300, 302], "ye": 221, "yellow": 219, "yet": [293, 296], "yield": [167, 207], "you": [14, 208, 209, 228, 289, 290, 293, 295, 296, 298, 299, 301], "your": [195, 289, 290, 292, 295, 296, 298, 299, 300], "your_password": 292, "your_usernam": 292, "z": [45, 171], "zapit": 288, "zero": [176, 196, 202, 222, 237], "zip": 289, "\u03bcl": 26}, "titles": ["API Reference", "iblrig", "iblrig.base_choice_world", "iblrig.base_choice_world.ActiveChoiceWorldSession", "iblrig.base_choice_world.ActiveChoiceWorldTrialData", "iblrig.base_choice_world.BiasedChoiceWorldSession", "iblrig.base_choice_world.BiasedChoiceWorldTrialData", "iblrig.base_choice_world.ChoiceWorldSession", "iblrig.base_choice_world.ChoiceWorldTrialData", "iblrig.base_choice_world.HabituationChoiceWorldSession", "iblrig.base_choice_world.HabituationChoiceWorldTrialData", "iblrig.base_choice_world.TrainingChoiceWorldSession", "iblrig.base_choice_world.TrainingChoiceWorldTrialData", "iblrig.base_tasks", "iblrig.base_tasks.BaseSession", "iblrig.base_tasks.BonsaiRecordingMixin", "iblrig.base_tasks.BonsaiVisualStimulusMixin", "iblrig.base_tasks.BpodMixin", "iblrig.base_tasks.EmptySession", "iblrig.base_tasks.Frame2TTLMixin", "iblrig.base_tasks.HasBpod", "iblrig.base_tasks.NetworkSession", "iblrig.base_tasks.OSCClient", "iblrig.base_tasks.RotaryEncoderMixin", "iblrig.base_tasks.SoundMixin", "iblrig.base_tasks.SpontaneousSession", "iblrig.base_tasks.ValveMixin", "iblrig.choiceworld", "iblrig.choiceworld.compute_adaptive_reward_volume", "iblrig.choiceworld.contrasts_set", "iblrig.choiceworld.draw_training_contrast", "iblrig.choiceworld.get_subject_training_info", "iblrig.choiceworld.training_contrasts_probabilities", "iblrig.choiceworld.training_phase_from_contrast_set", "iblrig.commands", "iblrig.commands.dir_path", "iblrig.commands.flush", "iblrig.commands.remove_local_sessions", "iblrig.commands.transfer_data", "iblrig.commands.transfer_data_cli", "iblrig.commands.transfer_ephys_data_cli", "iblrig.commands.transfer_video_data_cli", "iblrig.commands.view_session", "iblrig.constants", "iblrig.ephys", "iblrig.ephys.neuropixel24_micromanipulator_coordinates", "iblrig.ephys.prepare_ephys_session", "iblrig.ephys.prepare_ephys_session_cmd", "iblrig.frame2ttl", "iblrig.frame2ttl.Frame2TTL", "iblrig.graphic", "iblrig.graphic.numinput", "iblrig.gui", "iblrig.gui.frame2ttl", "iblrig.gui.frame2ttl.Frame2TTLCalibrationDialog", "iblrig.gui.frame2ttl.Frame2TTLCalibrationTarget", "iblrig.gui.resources_rc", "iblrig.gui.resources_rc.qCleanupResources", "iblrig.gui.resources_rc.qInitResources", "iblrig.gui.splash", "iblrig.gui.splash.Splash", "iblrig.gui.tab_about", "iblrig.gui.tab_about.TabAbout", "iblrig.gui.tab_data", "iblrig.gui.tab_data.Column", "iblrig.gui.tab_data.DataItemDelegate", "iblrig.gui.tab_data.DataWorker", "iblrig.gui.tab_data.TabData", "iblrig.gui.tab_data.sizeof_fmt", "iblrig.gui.tab_docs", "iblrig.gui.tab_docs.CustomWebEnginePage", "iblrig.gui.tab_docs.TabDocs", "iblrig.gui.tab_log", "iblrig.gui.tab_log.TabLog", "iblrig.gui.tools", "iblrig.gui.tools.AlyxObject", "iblrig.gui.tools.DataFrameTableModel", "iblrig.gui.tools.DiskSpaceIndicator", "iblrig.gui.tools.LineEditAlyxUser", "iblrig.gui.tools.RemoteDevicesItemModel", "iblrig.gui.tools.RemoteDevicesListView", "iblrig.gui.tools.StatefulButton", "iblrig.gui.tools.Worker", "iblrig.gui.tools.WorkerSignals", "iblrig.gui.tools.convert_uis", "iblrig.gui.ui_frame2ttl", "iblrig.gui.ui_frame2ttl.Ui_frame2ttl", "iblrig.gui.ui_login", "iblrig.gui.ui_login.Ui_login", "iblrig.gui.ui_splash", "iblrig.gui.ui_splash.Ui_splash", "iblrig.gui.ui_tab_about", "iblrig.gui.ui_tab_about.Ui_TabAbout", "iblrig.gui.ui_tab_data", "iblrig.gui.ui_tab_data.Ui_TabData", "iblrig.gui.ui_tab_docs", "iblrig.gui.ui_tab_docs.Ui_TabDocs", "iblrig.gui.ui_tab_log", "iblrig.gui.ui_tab_log.Ui_TabLog", "iblrig.gui.ui_tab_session", "iblrig.gui.ui_tab_session.Ui_tabSession", "iblrig.gui.ui_update", "iblrig.gui.ui_update.Ui_update", "iblrig.gui.ui_validation", "iblrig.gui.ui_validation.Ui_validation", "iblrig.gui.ui_valve", "iblrig.gui.ui_valve.Ui_valve", "iblrig.gui.ui_wizard", "iblrig.gui.ui_wizard.Ui_wizard", "iblrig.gui.validation", "iblrig.gui.validation.StatusItem", "iblrig.gui.validation.SystemValidationDialog", "iblrig.gui.validation.ValidatorItem", "iblrig.gui.valve", "iblrig.gui.valve.CalibrationPlot", "iblrig.gui.valve.ValveCalibrationDialog", "iblrig.gui.wizard", "iblrig.gui.wizard.LoginWindow", "iblrig.gui.wizard.RigWizard", "iblrig.gui.wizard.RigWizardModel", "iblrig.gui.wizard.UpdateNotice", "iblrig.gui.wizard.main", "iblrig.hardware", "iblrig.hardware.Bpod", "iblrig.hardware.MyRotaryEncoder", "iblrig.hardware.SOFTCODE", "iblrig.hardware.restart_com_port", "iblrig.hardware.sound_device_factory", "iblrig.hardware_validation", "iblrig.hardware_validation.Result", "iblrig.hardware_validation.Status", "iblrig.hardware_validation.ValidateHardwareError", "iblrig.hardware_validation.Validator", "iblrig.hardware_validation.ValidatorAlyx", "iblrig.hardware_validation.ValidatorAmbientModule", "iblrig.hardware_validation.ValidatorBpod", "iblrig.hardware_validation.ValidatorCamera", "iblrig.hardware_validation.ValidatorFrame2TTL", "iblrig.hardware_validation.ValidatorGit", "iblrig.hardware_validation.ValidatorMic", "iblrig.hardware_validation.ValidatorRotaryEncoderModule", "iblrig.hardware_validation.ValidatorSerial", "iblrig.hardware_validation.ValidatorSound", "iblrig.hardware_validation.ValidatorValve", "iblrig.hardware_validation.get_all_validators", "iblrig.hardware_validation.run_all_validators", "iblrig.hardware_validation.run_all_validators_cli", "iblrig.hifi", "iblrig.hifi.HiFi", "iblrig.hifi.HiFiException", "iblrig.misc", "iblrig.misc.draw_contrast", "iblrig.misc.get_biased_probs", "iblrig.misc.get_port_events", "iblrig.misc.get_session_path", "iblrig.misc.get_task_argument_parser", "iblrig.misc.get_task_arguments", "iblrig.misc.online_std", "iblrig.misc.truncated_exponential", "iblrig.net", "iblrig.net.Auxiliaries", "iblrig.net.ExpInfo", "iblrig.net.check_uri_match", "iblrig.net.get_remote_devices", "iblrig.net.get_remote_devices_file", "iblrig.net.get_server_communicator", "iblrig.net.install_alyx_token", "iblrig.net.read_stdin", "iblrig.net.update_alyx_token", "iblrig.online_plots", "iblrig.online_plots.DataModel", "iblrig.online_plots.OnlinePlots", "iblrig.path_helper", "iblrig.path_helper.create_bonsai_layout_from_template", "iblrig.path_helper.get_commit_hash", "iblrig.path_helper.get_local_and_remote_paths", "iblrig.path_helper.iterate_collection", "iblrig.path_helper.iterate_previous_sessions", "iblrig.path_helper.load_pydantic_yaml", "iblrig.path_helper.patch_settings", "iblrig.path_helper.save_pydantic_yaml", "iblrig.pydantic_definitions", "iblrig.pydantic_definitions.BunchModel", "iblrig.pydantic_definitions.ExistingFilePath", "iblrig.pydantic_definitions.HardwareSettings", "iblrig.pydantic_definitions.HardwareSettingsBpod", "iblrig.pydantic_definitions.HardwareSettingsCamera", "iblrig.pydantic_definitions.HardwareSettingsCameraWorkflow", "iblrig.pydantic_definitions.HardwareSettingsFrame2TTL", "iblrig.pydantic_definitions.HardwareSettingsMicrophone", "iblrig.pydantic_definitions.HardwareSettingsRotaryEncoder", "iblrig.pydantic_definitions.HardwareSettingsScale", "iblrig.pydantic_definitions.HardwareSettingsScreen", "iblrig.pydantic_definitions.HardwareSettingsSound", "iblrig.pydantic_definitions.HardwareSettingsValve", "iblrig.pydantic_definitions.RigSettings", "iblrig.pydantic_definitions.TrialDataModel", "iblrig.raw_data_loaders", "iblrig.raw_data_loaders.load_task_jsonable", "iblrig.rig_component", "iblrig.rig_component.RigComponent", "iblrig.scale", "iblrig.scale.Scale", "iblrig.scale.ScaleData", "iblrig.serial_singleton", "iblrig.serial_singleton.SerialSingleton", "iblrig.serial_singleton.SerialSingletonException", "iblrig.serial_singleton.filter_ports", "iblrig.serial_singleton.get_port_from_serial_number", "iblrig.serial_singleton.get_serial_number_from_port", "iblrig.session_creator", "iblrig.session_creator.draw_block_len", "iblrig.session_creator.draw_position", "iblrig.session_creator.make_ephyscw_pc", "iblrig.sound", "iblrig.sound.configure_sound_card", "iblrig.sound.format_sound", "iblrig.sound.make_sound", "iblrig.tools", "iblrig.tools.ANSI", "iblrig.tools.alyx_reachable", "iblrig.tools.ask_user", "iblrig.tools.call_bonsai", "iblrig.tools.call_bonsai_async", "iblrig.tools.get_anydesk_id", "iblrig.tools.get_inheritors", "iblrig.tools.get_lab_location_dict", "iblrig.tools.internet_available", "iblrig.tools.static_vars", "iblrig.transfer_experiments", "iblrig.transfer_experiments.BehaviorCopier", "iblrig.transfer_experiments.CopyState", "iblrig.transfer_experiments.EphysCopier", "iblrig.transfer_experiments.SessionCopier", "iblrig.transfer_experiments.VideoCopier", "iblrig.transfer_experiments.copy_folders", "iblrig.upgrade_iblrig", "iblrig.upgrade_iblrig.call_subprocesses", "iblrig.upgrade_iblrig.upgrade", "iblrig.valve", "iblrig.valve.Valve", "iblrig.valve.ValveValues", "iblrig.version_management", "iblrig.version_management.call_git", "iblrig.version_management.check_for_updates", "iblrig.version_management.check_upgrade_prerequisites", "iblrig.version_management.get_branch", "iblrig.version_management.get_changelog", "iblrig.version_management.get_commit_hash", "iblrig.version_management.get_detailed_version_string", "iblrig.version_management.get_local_version", "iblrig.version_management.get_remote_tags", "iblrig.version_management.get_remote_version", "iblrig.version_management.is_dirty", "iblrig_tasks", "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld", "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task", "iblrig_tasks._iblrig_tasks_ImagingChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_advancedChoiceWorld", "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task", "iblrig_tasks._iblrig_tasks_advancedChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_biasedChoiceWorld", "iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task", "iblrig_tasks._iblrig_tasks_biasedChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_ephysChoiceWorld", "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task", "iblrig_tasks._iblrig_tasks_ephysChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_habituationChoiceWorld", "iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task", "iblrig_tasks._iblrig_tasks_habituationChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld", "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task", "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.NeuroModulatorChoiceTrialData", "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_neuroModulatorChoiceWorld.task.SessionRelatedBlocks", "iblrig_tasks._iblrig_tasks_passiveChoiceWorld", "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task", "iblrig_tasks._iblrig_tasks_passiveChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_spontaneous", "iblrig_tasks._iblrig_tasks_spontaneous.task", "iblrig_tasks._iblrig_tasks_spontaneous.task.Session", "iblrig_tasks._iblrig_tasks_trainingChoiceWorld", "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task", "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.Session", "iblrig_tasks._iblrig_tasks_trainingChoiceWorld.task.float_or_none", "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld", "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task", "iblrig_tasks._iblrig_tasks_trainingPhaseChoiceWorld.task.Session", "Changelog", "Frequently Asked Questions", "Hardware Guide", "IBLRIG", "Installation guide", "Reference", "Describing an Experiment", "Developer Guide", "Quality check the task post-usage", "Guide to develop a custom task", "Using IBLRIG v8", "Running a behaviour experiment", "Copy commands", "Neuropixel recording with iblrigv8", "Video acquisition computer"], "titleterms": {"0": 288, "1": [288, 293, 297], "10": [288, 292], "11": 288, "12": 288, "13": 288, "14": 288, "15": 288, "16": 288, "17": 288, "18": 288, "19": 288, "2": [288, 293, 297], "20": 288, "21": 288, "22": 288, "23": 288, "24": 288, "3": [288, 292], "4": 288, "5": 288, "6": 288, "7": 288, "8": 288, "9": 288, "ONE": 292, "The": [298, 299], "_iblrig_tasks_advancedchoiceworld": [258, 259, 260], "_iblrig_tasks_biasedchoiceworld": [261, 262, 263], "_iblrig_tasks_ephyschoiceworld": [264, 265, 266], "_iblrig_tasks_habituationchoiceworld": [267, 268, 269], "_iblrig_tasks_imagingchoiceworld": [255, 256, 257], "_iblrig_tasks_neuromodulatorchoiceworld": [270, 271, 272, 273, 274], "_iblrig_tasks_passivechoiceworld": [275, 276, 277], "_iblrig_tasks_spontan": [278, 279, 280], "_iblrig_tasks_trainingchoiceworld": [281, 282, 283, 284], "_iblrig_tasks_trainingphasechoiceworld": [285, 286, 287], "acquir": [293, 296], "acquisit": [298, 302], "activechoiceworldsess": 3, "activechoiceworldtrialdata": 4, "ae": 290, "after": [293, 296], "aid": 289, "alyx": [292, 293, 296, 298, 299], "alyx_reach": 220, "alyxobject": 75, "an": [293, 294], "ansi": 219, "api": 0, "ask": 289, "ask_us": 221, "auxiliari": 160, "background": [290, 292], "base_choice_world": [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], "base_task": [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26], "basesess": 14, "behaviorcopi": 230, "behaviour": [298, 299], "behind": [298, 300], "bias": [293, 297], "biasedchoiceworldsess": 5, "biasedchoiceworldtrialdata": 6, "bonsai": 289, "bonsairecordingmixin": 15, "bonsaivisualstimulusmixin": 16, "bpod": [123, 290], "bpodmixin": 17, "break": [293, 294], "bug": 289, "build": 295, "bunchmodel": 182, "c": 292, "calibrationplot": 114, "call_bonsai": 222, "call_bonsai_async": 223, "call_git": 243, "call_subprocess": 237, "camera": 289, "can": 292, "chain": [298, 299], "changelog": 288, "check": [292, 293, 296], "check_for_upd": 244, "check_upgrade_prerequisit": 245, "check_uri_match": 162, "checklist": 295, "choic": [293, 297], "choiceworld": [27, 28, 29, 30, 31, 32, 33], "choiceworldsess": 7, "choiceworldtrialdata": 8, "clean": [298, 300], "column": 64, "command": [34, 35, 36, 37, 38, 39, 40, 41, 42, 298, 299, 300, 301, 302], "commit": 295, "compon": [293, 294], "comput": [298, 302], "compute_adaptive_reward_volum": 28, "config": [298, 302], "configur": 292, "configure_sound_card": 215, "connect": 292, "constant": 43, "contrasts_set": 29, "contribut": 295, "control": [298, 299], "convert_ui": 84, "copi": [298, 300, 301, 302], "copy_fold": 235, "copyst": 231, "creat": [293, 297], "create_bonsai_layout_from_templ": 173, "custom": [293, 297], "customwebenginepag": 70, "data": [298, 300, 301], "dataframetablemodel": 76, "dataitemdeleg": 65, "datamodel": 170, "datawork": 66, "default": 289, "defin": 289, "definit": [293, 296], "depend": 295, "describ": [293, 294], "descript": [293, 294], "design": [293, 297], "develop": [293, 295, 297], "devic": [293, 294], "dir_path": 35, "diskspaceind": 77, "document": 295, "down": [293, 294], "draw_block_len": 211, "draw_contrast": 151, "draw_posit": 212, "draw_training_contrast": 30, "driver": [298, 302], "emptysess": 18, "ephi": [44, 45, 46, 47], "ephyscopi": 232, "everyth": 292, "exampl": [126, 159, 176, 207, 293, 297, 298, 300], "existingfilepath": 183, "experi": [293, 294, 298, 299], "expinfo": 161, "featur": 289, "file": [292, 293, 294], "filter_port": 207, "fine": 292, "first": 289, "float_or_non": 284, "flush": [36, 298, 299], "format": 295, "format_sound": 216, "frame2ttl": [48, 49, 53, 54, 55, 289], "frame2ttlcalibrationdialog": 54, "frame2ttlcalibrationtarget": 55, "frame2ttlmixin": 19, "frequent": 289, "gener": 289, "get_all_valid": 144, "get_anydesk_id": 224, "get_biased_prob": 152, "get_branch": 246, "get_changelog": 247, "get_commit_hash": [174, 248], "get_detailed_version_str": 249, "get_inheritor": 225, "get_lab_location_dict": 226, "get_local_and_remote_path": 175, "get_local_vers": 250, "get_port_ev": 153, "get_port_from_serial_numb": 208, "get_remote_devic": 163, "get_remote_devices_fil": 164, "get_remote_tag": 251, "get_remote_vers": 252, "get_serial_number_from_port": 209, "get_server_commun": 165, "get_session_path": 154, "get_subject_training_info": 31, "get_task_argu": 156, "get_task_argument_pars": 155, "graphic": [50, 51, 298, 299], "gui": [52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121], "guid": [290, 292, 293, 295, 297], "habituationchoiceworldsess": 9, "habituationchoiceworldtrialdata": 10, "hardwar": [122, 123, 124, 125, 126, 127, 290], "hardware_valid": [128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146], "hardwareset": 184, "hardwaresettingsbpod": 185, "hardwaresettingscamera": 186, "hardwaresettingscameraworkflow": 187, "hardwaresettingsframe2ttl": 188, "hardwaresettingsmicrophon": 189, "hardwaresettingsrotaryencod": 190, "hardwaresettingsscal": 191, "hardwaresettingsscreen": 192, "hardwaresettingssound": 193, "hardwaresettingsvalv": 194, "hasbpod": 20, "hifi": [147, 148, 149, 290], "hifiexcept": 149, "how": [293, 296], "i": [293, 296], "iblrig": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 291, 292, 298], "iblrig_task": [254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287], "iblrigv8": [292, 293, 297, 298, 301], "immedi": [293, 296], "inherit": [293, 297], "instal": [292, 295, 298, 302], "install_alyx_token": 166, "instruct": 292, "interfac": [298, 299], "internet_avail": 227, "is_dirti": 253, "issu": 289, "iterate_collect": 176, "iterate_previous_sess": 177, "level": [293, 296], "line": [298, 299], "lineeditalyxus": 78, "link": 291, "lint": 295, "load_pydantic_yaml": 178, "load_task_json": 198, "local": [298, 300], "loginwindow": 117, "look": [298, 301], "machin": [293, 297], "main": 121, "make": 292, "make_ephyscw_pc": 213, "make_sound": 217, "manag": 295, "metric": [293, 296], "misc": [150, 151, 152, 153, 154, 155, 156, 157, 158], "modul": 290, "myrotaryencod": 124, "net": [159, 160, 161, 162, 163, 164, 165, 166, 167, 168], "networksess": 21, "neuromodulatorchoicetrialdata": 272, "neuropixel": [298, 301], "neuropixel24_micromanipulator_coordin": 45, "note": [7, 158, 207, 224, 247, 249, 251, 252], "numinput": 51, "onc": [293, 296], "online_plot": [169, 170, 171], "online_std": 157, "onlineplot": 171, "oscclient": 22, "outcom": [293, 296], "own": [293, 297], "packag": 295, "patch_set": 179, "path_help": [172, 173, 174, 175, 176, 177, 178, 179, 180], "pdm": 295, "posit": 289, "post": [293, 296], "powershel": 292, "pre": 295, "prepar": 292, "prepare_ephys_sess": 46, "prepare_ephys_session_cmd": 47, "prerequisit": 292, "procedur": [290, 293, 294], "project": [293, 294], "pydantic_definit": [181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196], "python": 292, "qc": [293, 296], "qcleanupresourc": 57, "qinitresourc": 58, "qualiti": [293, 296], "quantifi": [293, 296], "question": 289, "raw": [298, 301], "raw_data_load": [197, 198], "re": [293, 297], "read_stdin": 167, "record": [298, 301], "redistribut": 292, "refer": [0, 293], "regist": [293, 296], "releas": 295, "remotedevicesitemmodel": 79, "remotedeviceslistview": 80, "remove_local_sess": 37, "report": 289, "request": 289, "requir": 290, "resources_rc": [56, 57, 58], "restart_com_port": 126, "result": 129, "rig": 292, "rig_compon": [199, 200], "rigcompon": 200, "rigset": 195, "rigwizard": 118, "rigwizardmodel": 119, "rotaryencodermixin": 23, "run": [292, 293, 295, 296, 298, 299], "run_all_valid": 145, "run_all_validators_cli": 146, "save_pydantic_yaml": 180, "scale": [201, 202, 203], "scaledata": 203, "scheme": 295, "screen": 289, "script": [298, 300], "serial_singleton": [204, 205, 206, 207, 208, 209], "serialsingleton": 205, "serialsingletonexcept": 206, "session": [257, 260, 263, 266, 269, 273, 277, 280, 283, 287, 293, 296], "session_cr": [210, 211, 212, 213], "sessioncopi": 233, "sessionrelatedblock": 274, "set": [292, 298, 302], "setup": [298, 301, 302], "sever": [298, 299], "singl": [298, 299], "size": 289, "sizeof_fmt": 68, "softcod": 125, "sound": [214, 215, 216, 217, 289], "sound_device_factori": 127, "soundmixin": 24, "specif": 292, "splash": [59, 60], "spontaneoussess": 25, "start": [298, 299, 301, 302], "state": [293, 297], "statefulbutton": 81, "static_var": 228, "statu": 130, "statusitem": 110, "suit": 292, "supplementari": [298, 299], "sure": 292, "switch": 292, "sync": [293, 294], "systemvalidationdialog": 111, "tab_about": [61, 62], "tab_data": [63, 64, 65, 66, 67, 68], "tab_doc": [69, 70, 71], "tab_log": [72, 73], "tababout": 62, "tabdata": 67, "tabdoc": 71, "tablog": 73, "task": [256, 257, 259, 260, 262, 263, 265, 266, 268, 269, 271, 272, 273, 274, 276, 277, 279, 280, 282, 283, 284, 286, 287, 293, 294, 296, 297, 298, 299, 301, 302], "test": [292, 295], "togeth": [298, 299], "tool": [74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228], "training_contrasts_prob": 32, "training_phase_from_contrast_set": 33, "trainingchoiceworldsess": 11, "trainingchoiceworldtrialdata": 12, "transfer_data": 38, "transfer_data_cli": 39, "transfer_ephys_data_cli": 40, "transfer_experi": [229, 230, 231, 232, 233, 234, 235], "transfer_video_data_cli": 41, "trialdatamodel": 196, "truncated_exponenti": 158, "ui_frame2ttl": [85, 86], "ui_login": [87, 88], "ui_splash": [89, 90], "ui_tab_about": [91, 92], "ui_tab_data": [93, 94], "ui_tab_doc": [95, 96], "ui_tab_log": [97, 98], "ui_tab_sess": [99, 100], "ui_tababout": 92, "ui_tabdata": 94, "ui_tabdoc": 96, "ui_tablog": 98, "ui_tabsess": 100, "ui_upd": [101, 102], "ui_valid": [103, 104], "ui_valv": [105, 106], "ui_wizard": [107, 108], "unit": 295, "up": [292, 298, 300], "updat": 292, "update_alyx_token": 168, "updatenotic": 120, "upgrad": [238, 290], "upgrade_iblrig": [236, 237, 238], "us": 298, "usag": [293, 296, 298, 300, 301, 302], "user": [298, 299], "v8": 298, "valid": [109, 110, 111, 112, 132], "validatehardwareerror": 131, "validatoralyx": 133, "validatorambientmodul": 134, "validatorbpod": 135, "validatorcamera": 136, "validatorframe2ttl": 137, "validatorgit": 138, "validatoritem": 112, "validatorm": 139, "validatorrotaryencodermodul": 140, "validatorseri": 141, "validatorsound": 142, "validatorvalv": 143, "valv": [113, 114, 115, 239, 240, 241, 298, 299], "valvecalibrationdialog": 115, "valvemixin": 26, "valvevalu": 241, "variat": [293, 297], "version": [292, 293, 294, 295], "version_manag": [242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253], "video": [298, 302], "videocopi": 234, "view_sess": 42, "viewer": [293, 296], "visual": [289, 292], "went": 292, "where": [293, 297], "window": 292, "wizard": [116, 117, 118, 119, 120, 121], "worker": 82, "workersign": 83, "workflow": [295, 298, 300], "world": [293, 297], "write": [293, 297], "xonar": 290, "you": 292, "your": [293, 297]}}) \ No newline at end of file diff --git a/usage.html b/usage.html new file mode 100644 index 000000000..b7b6ab418 --- /dev/null +++ b/usage.html @@ -0,0 +1,560 @@ + + + + + + + Using IBLRIG v8 — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Using IBLRIG v8

+
+

Running a behaviour experiment

+

IBLRIG v8 provides users with two distinct interfaces: a command line interface (CLI) and a graphical user interface (GUI). +The CLI encompasses the complete functionality of IBLRIG, upon which the GUI is constructed to enhance user-friendliness. +All tasks achievable through the GUI are equally achievable through the CLI.

+
+

The Graphical User Interface

+

To initiate a task through the graphical user interface, open a Windows PowerShell and enter:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+iblrig
+
+
+

These commands activate the necessary environment and launch the IBLRIG Wizard GUI as shown below:

+
+A screenshot of IBL Rig Wizard +
+

A screenshot of IBLRIG Wizard

+
+
+
+

Starting a Task

+
    +
  1. Enter your Alyx username, then click on the Connect button. This +action will automatically populate the GUI fields with information +pertinent to your lab.

  2. +
  3. Select the desired values from the provided options. Utilize the +Filter field to swiftly narrow down the list of displayed subjects. +Note that selections for Project and Procedure are mandatory.

  4. +
  5. Click the Start button to initiate the task.

  6. +
+
+
+

Supplementary Controls

+
    +
  • When starting a subsequent task with the same subject, you’ll be asked if +you want to append to the preceding session. Doing so will result in a +sequence of connected tasks sharing the same data folder.

  • +
  • The Flush button serves to toggle the valve for cleaning purposes.

  • +
+
+

Note

+

IBLRIG’s Graphical User Interface is still work-in-progress. If you have any suggestions to make the GUI +more usable, please add an issue on GitHub or approach the dev-team on Slack! +We are happy to discuss possible changes with you!

+
+
+
+
+

Interfacing with Alyx

+

Although this is not mandatory, the IBLRIG GUI is designed to interface with Alyx, the International Brain Laboratory’s database. +This feature allows users to access their subjects and projects directly from the GUI, without the need to manually enter this information.

+

To enable this feature, you must have an Alyx account and have configured your database URL and credentials as mentioned Installation guide.

+
    +
  • The subjects available are the set of alyx subjects that are alive, not stock, and belong to the lab defined in the iblrig_settings.py file.

  • +
  • The projects available are the set of projects of which the current user is a participant. Login to Alyx > Subjects > Projects to check your projects.

  • +
+
+
+

The Command Line Interface

+

To use the command line interface, open a terminal and activate the +environment:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+
+
+
+

Running a single task

+

To run a single task, execute the following command:

+
python .\iblrig_tasks\_iblrig_tasks_trainingChoiceWorld\task.py --subject algernon --user john.doe
+
+
+
+
+

Chaining several tasks together

+

To chain several tasks together, use the --append flag. For +instance, to run a passive task after an ephys task:

+
    +
  1. Run the ephys task

    +
    .\iblrig_tasks\_iblrig_tasks_ephysChoiceWorld\task.py --subject algernon
    +
    +
    +
  2. +
  3. Run the passive task with the --appendflag:

    +
    .\iblrig_tasks\_iblrig_tasks_passiveChoiceWorld\task.py --subject algernon --append
    +
    +
    +
  4. +
+
+
+

Flushing the valve

+

To flush valve 1 of the Bpod, type flush and confirm with ENTER. Press ENTER again to close the valve.

+
+
+
+
+

Copy commands

+
+

Usage

+

To initiate the data transfer from the local server to the remote +server, open a terminal and type.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag behavior
+
+
+

The transfer local and remote directories are set in the +iblrig/settings/iblrig_settings.py file.

+

To copy data at another acquisition PC, such as video and ephys, use the relevant tag, e.g.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag video
+
+
+

NB: By default the local data that was copied over 2 weeks ago will be automatically removed. To +avoid this set the cleanup-weeks argument to -1:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data behavior --cleanup-weeks -1
+
+
+

See the ‘Clean-up local data’ section on how to remove data without calling the copy script.

+

To view the copy status of your local sessions without actually copying, use the ‘dry’ argument:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data behavior --dry
+
+
+

For more information on the tranfer_data arguments, use the help flag:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --help
+
+
+
+
+

Clean-up local data

+

To remove sessions fully copied to the server and older than 2 weeks, +open a terminal and type:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+remove-old-sessions
+
+
+

Note: the server needs to be up and running or the sessions won’t be +verified as copied.

+
+
+

Behind the Copy Scripts

+
+

Workflow

+
    +
  1. Initial Stub Creation: At the start of acquisition, an incomplete +experiment description file - a ‘stub’ - is saved to the session +on, both, the local PC and the lab server in a subfolder called +_devices. The filename of the stub includes the PC’s identifier, +allowing the copy script to identify its source.

  2. +
  3. Executing the Copy Script: The copy script is executed on each +acquisition PC independently and in no particular order.

  4. +
  5. Navigating Local Session Data: The script systematically +navigates through local session folders (or optionally a separate +transfers folder) that contain experiment.description stubs.

  6. +
  7. Skipping Transferred Sessions: The script ignores session folders +containing a file named transferred.flag (see 7).

  8. +
  9. Copying Collections: For each session, the script reads the +respective stub and uses rsync to copy each collection. +Subfolders not specified under a collection key are omitted from +copying.

  10. +
  11. Removing Remote Stubs: Upon successful copying, the remote stub +file is merged with the remote experiment.description file (or +copied over if one doesn’t exist already). The remote stub file is +then deleted.

  12. +
  13. Confirming Transfer Locally: A transferred.flag file is +created in the local session folder to confirm the transfer’s +success.

  14. +
  15. Completion and Cleanup: Once no more remote stub files exist +for a given session, the empty _devices subfolder is removed. +Additionally, a ‘raw_session.flag’ file is created in the remote session folder, +indicating the successful transfer of all files.

  16. +
+
+
+

Example of workflow

+

Example of three sessions each in a different copy state:

+
    +
  • The State on the Remote Lab Server

    +
    lab server/
    +└── subject/
    +    └── 2020-01-01/
    +        ├── 001/
    +        │   └── _devices/
    +        │       ├── 2020-01-01_1_subject@taskPC.yaml
    +        │       └── 2020-01-01_1_subject@ephysPC.yaml
    +        ├── 002/
    +        │   ├── _ibl_experiment.description.yaml
    +        │   ├── raw_task_data_00/
    +        │   └── _devices/
    +        │       └── 2020-01-01_1_subject@ephysPC.yaml
    +        └── 003/
    +            ├── raw_task_data_00/
    +            ├── raw_ephys_data/
    +            ├── _ibl_experiment.description.yaml
    +            └── raw_session.flag
    +
    +
    +
  • +
  • The State on the Local Task Acquisition PC

    +
    acquisition computer (taskPC)/
    +└── subject/
    +    └── 2020-01-01/
    +        ├── 001/
    +        │   ├── raw_task_data_00/
    +        │   └── _ibl_experiment.description_taskPC.yaml
    +        ├── 002/
    +        │   ├── raw_task_data_00/
    +        │   ├── _ibl_experiment.description_taskPC.yaml
    +        │   └── transferred.flag
    +        └── 003/
    +            ├── raw_task_data_00/
    +            ├── folder_not_in_desc_file/
    +            ├── _ibl_experiment.description_taskPC.yaml
    +            └── transferred.flag
    +
    +
    +
  • +
  • +
    The State on the Local Ephys Acquisition PC
    acquisition computer (ephysPC)/
    +└── subject/
    +    └── 2020-01-01/
    +        ├── 001/
    +        │   ├── raw_ephys_data/
    +        │   └── _ibl_experiment.description_ephysPC.yaml
    +        ├── 002/
    +        │   ├── raw_ephys_data/
    +        │   ├── _ibl_experiment.description_ephysPC.yaml
    +        └── 003/
    +            ├── raw_ephys_data/
    +            ├── folder_not_in_desc_file/
    +            ├── _ibl_experiment.description_ephysPC.yaml
    +            └── transferred.flag
    +
    +
    +
    +
    +
  • +
+

With the lab server and acquisition pcs in the states above, the +sessions are in the following states

+
    +
  • subject/2020-01-01/001 no data have been copied.

  • +
  • subject/2020-01-01/002 data from taskPC have been copied, data from ephysPC remains to be copied.

  • +
  • subject/2020-01-01/003 data copied from all acquisition PCs.

  • +
+
+
+
+
+

Video acquisition computer

+

Video can be run on a separate computer, which is recommended when recording multiple cameras.

+
+

Setup

+
+

Installing drivers

+

Both spinnaker and pyspin must be installed before running an experiment:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+install_spinnaker
+install_pyspin
+
+
+
+
+

Settings config

+

The camera acquisition is configured by parameters in the ‘device_cameras’ key of the hardware_settings.yaml file. +Below is an overview of the parameters:

+
device_cameras:
+  # The name of the configuration. This is passed to the CLI.
+  default:
+    # This is required: the Bonsai workflows to be called by the CLI script.
+    BONSAI_WORKFLOW:
+      # Optional setup (e.g. alignment) workflow
+      setup: devices/camera_setup/EphysRig_SetupCameras.bonsai
+      # Required workflow to be called when the experiment starts
+      recording: devices/camera_recordings/TrainingRig_SaveVideo_TrainingTasks.bonsai
+    # Camera #1 name
+    left:
+      # Required camera device index (assigned in driver software)
+      INDEX: 1
+      # Optional expected frame height. Actual resolution should be set in the driver software.
+      HEIGHT: 1024
+      # Optional expected frame width. This is simply used in QC.
+      WIDTH: 1280
+      # Optional expected frame rate (Hz). This is simply used in QC.
+      FPS: 30
+
+
+

Multiple configurations can be added, e.g. ‘default’, ‘training’, ‘ephys’, etc. and within each, multiple cameras +can be added, e.g. ‘left’, ‘right’, ‘body’, etc. Each configuration requires a BONSAI_WORKFLOW: recording key; +each camera requires an INDEX key.

+
+
+
+

Starting a task

+

Below shows how to start the cameras for the subject ‘example’ with configuration ‘default’:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+start_video_session example default
+
+
+
+
+

Copy command

+
+

Usage

+

To initiate the data transfer from the local server to the remote server, open a terminal and type.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag video
+
+
+

The transfer local and remote directories are set in the +iblrig/settings/iblrig_settings.py file.

+
+
+
+
+

Neuropixel recording with iblrigv8

+

This document describes how to use the iblrigv8 software to record from the Neuropixel computer.

+
+

Setup

+

Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer.

+

To get access to the viewephys visualizer:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+pip install viewephys
+
+
+
+
+

Starting a task

+

Below shows how to start the electrophysiology for the subject ‘example’ with 2 probes:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+start_ephys_session example 2
+
+
+
+
+

Copy command

+
+

Usage

+

To initiate the data transfer from the local server to the remote server, open a terminal and type.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag ephys
+
+
+

The transfer local and remote directories are set in the +iblrig/settings/iblrig_settings.py file.

+
+
+
+

Look at the raw data

+

This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display.

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+viewephys
+
+
+Alternative text +

More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/usage_behavior.html b/usage_behavior.html new file mode 100644 index 000000000..80f09690b --- /dev/null +++ b/usage_behavior.html @@ -0,0 +1,230 @@ + + + + + + + Running a behaviour experiment — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Running a behaviour experiment

+

IBLRIG v8 provides users with two distinct interfaces: a command line interface (CLI) and a graphical user interface (GUI). +The CLI encompasses the complete functionality of IBLRIG, upon which the GUI is constructed to enhance user-friendliness. +All tasks achievable through the GUI are equally achievable through the CLI.

+
+

The Graphical User Interface

+

To initiate a task through the graphical user interface, open a Windows PowerShell and enter:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+iblrig
+
+
+

These commands activate the necessary environment and launch the IBLRIG Wizard GUI as shown below:

+
+A screenshot of IBL Rig Wizard +
+

A screenshot of IBLRIG Wizard

+
+
+
+

Starting a Task

+
    +
  1. Enter your Alyx username, then click on the Connect button. This +action will automatically populate the GUI fields with information +pertinent to your lab.

  2. +
  3. Select the desired values from the provided options. Utilize the +Filter field to swiftly narrow down the list of displayed subjects. +Note that selections for Project and Procedure are mandatory.

  4. +
  5. Click the Start button to initiate the task.

  6. +
+
+
+

Supplementary Controls

+
    +
  • When starting a subsequent task with the same subject, you’ll be asked if +you want to append to the preceding session. Doing so will result in a +sequence of connected tasks sharing the same data folder.

  • +
  • The Flush button serves to toggle the valve for cleaning purposes.

  • +
+
+

Note

+

IBLRIG’s Graphical User Interface is still work-in-progress. If you have any suggestions to make the GUI +more usable, please add an issue on GitHub or approach the dev-team on Slack! +We are happy to discuss possible changes with you!

+
+
+
+
+

Interfacing with Alyx

+

Although this is not mandatory, the IBLRIG GUI is designed to interface with Alyx, the International Brain Laboratory’s database. +This feature allows users to access their subjects and projects directly from the GUI, without the need to manually enter this information.

+

To enable this feature, you must have an Alyx account and have configured your database URL and credentials as mentioned Installation guide.

+
    +
  • The subjects available are the set of alyx subjects that are alive, not stock, and belong to the lab defined in the iblrig_settings.py file.

  • +
  • The projects available are the set of projects of which the current user is a participant. Login to Alyx > Subjects > Projects to check your projects.

  • +
+
+
+

The Command Line Interface

+

To use the command line interface, open a terminal and activate the +environment:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+
+
+
+

Running a single task

+

To run a single task, execute the following command:

+
python .\iblrig_tasks\_iblrig_tasks_trainingChoiceWorld\task.py --subject algernon --user john.doe
+
+
+
+
+

Chaining several tasks together

+

To chain several tasks together, use the --append flag. For +instance, to run a passive task after an ephys task:

+
    +
  1. Run the ephys task

    +
    .\iblrig_tasks\_iblrig_tasks_ephysChoiceWorld\task.py --subject algernon
    +
    +
    +
  2. +
  3. Run the passive task with the --appendflag:

    +
    .\iblrig_tasks\_iblrig_tasks_passiveChoiceWorld\task.py --subject algernon --append
    +
    +
    +
  4. +
+
+
+

Flushing the valve

+

To flush valve 1 of the Bpod, type flush and confirm with ENTER. Press ENTER again to close the valve.

+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/usage_copy.html b/usage_copy.html new file mode 100644 index 000000000..8f6ae8a20 --- /dev/null +++ b/usage_copy.html @@ -0,0 +1,290 @@ + + + + + + + Copy commands — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Copy commands

+
+

Usage

+

To initiate the data transfer from the local server to the remote +server, open a terminal and type.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag behavior
+
+
+

The transfer local and remote directories are set in the +iblrig/settings/iblrig_settings.py file.

+

To copy data at another acquisition PC, such as video and ephys, use the relevant tag, e.g.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag video
+
+
+

NB: By default the local data that was copied over 2 weeks ago will be automatically removed. To +avoid this set the cleanup-weeks argument to -1:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data behavior --cleanup-weeks -1
+
+
+

See the ‘Clean-up local data’ section on how to remove data without calling the copy script.

+

To view the copy status of your local sessions without actually copying, use the ‘dry’ argument:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data behavior --dry
+
+
+

For more information on the tranfer_data arguments, use the help flag:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --help
+
+
+
+
+

Clean-up local data

+

To remove sessions fully copied to the server and older than 2 weeks, +open a terminal and type:

+
C:\iblrigv8\venv\scripts\Activate.ps1
+remove-old-sessions
+
+
+

Note: the server needs to be up and running or the sessions won’t be +verified as copied.

+
+
+

Behind the Copy Scripts

+
+

Workflow

+
    +
  1. Initial Stub Creation: At the start of acquisition, an incomplete +experiment description file - a ‘stub’ - is saved to the session +on, both, the local PC and the lab server in a subfolder called +_devices. The filename of the stub includes the PC’s identifier, +allowing the copy script to identify its source.

  2. +
  3. Executing the Copy Script: The copy script is executed on each +acquisition PC independently and in no particular order.

  4. +
  5. Navigating Local Session Data: The script systematically +navigates through local session folders (or optionally a separate +transfers folder) that contain experiment.description stubs.

  6. +
  7. Skipping Transferred Sessions: The script ignores session folders +containing a file named transferred.flag (see 7).

  8. +
  9. Copying Collections: For each session, the script reads the +respective stub and uses rsync to copy each collection. +Subfolders not specified under a collection key are omitted from +copying.

  10. +
  11. Removing Remote Stubs: Upon successful copying, the remote stub +file is merged with the remote experiment.description file (or +copied over if one doesn’t exist already). The remote stub file is +then deleted.

  12. +
  13. Confirming Transfer Locally: A transferred.flag file is +created in the local session folder to confirm the transfer’s +success.

  14. +
  15. Completion and Cleanup: Once no more remote stub files exist +for a given session, the empty _devices subfolder is removed. +Additionally, a ‘raw_session.flag’ file is created in the remote session folder, +indicating the successful transfer of all files.

  16. +
+
+
+

Example of workflow

+

Example of three sessions each in a different copy state:

+
    +
  • The State on the Remote Lab Server

    +
    lab server/
    +└── subject/
    +    └── 2020-01-01/
    +        ├── 001/
    +        │   └── _devices/
    +        │       ├── 2020-01-01_1_subject@taskPC.yaml
    +        │       └── 2020-01-01_1_subject@ephysPC.yaml
    +        ├── 002/
    +        │   ├── _ibl_experiment.description.yaml
    +        │   ├── raw_task_data_00/
    +        │   └── _devices/
    +        │       └── 2020-01-01_1_subject@ephysPC.yaml
    +        └── 003/
    +            ├── raw_task_data_00/
    +            ├── raw_ephys_data/
    +            ├── _ibl_experiment.description.yaml
    +            └── raw_session.flag
    +
    +
    +
  • +
  • The State on the Local Task Acquisition PC

    +
    acquisition computer (taskPC)/
    +└── subject/
    +    └── 2020-01-01/
    +        ├── 001/
    +        │   ├── raw_task_data_00/
    +        │   └── _ibl_experiment.description_taskPC.yaml
    +        ├── 002/
    +        │   ├── raw_task_data_00/
    +        │   ├── _ibl_experiment.description_taskPC.yaml
    +        │   └── transferred.flag
    +        └── 003/
    +            ├── raw_task_data_00/
    +            ├── folder_not_in_desc_file/
    +            ├── _ibl_experiment.description_taskPC.yaml
    +            └── transferred.flag
    +
    +
    +
  • +
  • +
    The State on the Local Ephys Acquisition PC
    acquisition computer (ephysPC)/
    +└── subject/
    +    └── 2020-01-01/
    +        ├── 001/
    +        │   ├── raw_ephys_data/
    +        │   └── _ibl_experiment.description_ephysPC.yaml
    +        ├── 002/
    +        │   ├── raw_ephys_data/
    +        │   ├── _ibl_experiment.description_ephysPC.yaml
    +        └── 003/
    +            ├── raw_ephys_data/
    +            ├── folder_not_in_desc_file/
    +            ├── _ibl_experiment.description_ephysPC.yaml
    +            └── transferred.flag
    +
    +
    +
    +
    +
  • +
+

With the lab server and acquisition pcs in the states above, the +sessions are in the following states

+
    +
  • subject/2020-01-01/001 no data have been copied.

  • +
  • subject/2020-01-01/002 data from taskPC have been copied, data from ephysPC remains to be copied.

  • +
  • subject/2020-01-01/003 data copied from all acquisition PCs.

  • +
+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/usage_neuropixel.html b/usage_neuropixel.html new file mode 100644 index 000000000..7159e0672 --- /dev/null +++ b/usage_neuropixel.html @@ -0,0 +1,184 @@ + + + + + + + Neuropixel recording with iblrigv8 — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Neuropixel recording with iblrigv8

+

This document describes how to use the iblrigv8 software to record from the Neuropixel computer.

+
+

Setup

+

Just make sure iblrigv8 is installed according to the instructions and that the iblrig_settings.py +file is configured with the local folder and remote folder for the data transfer.

+

To get access to the viewephys visualizer:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+pip install viewephys
+
+
+
+
+

Starting a task

+

Below shows how to start the electrophysiology for the subject ‘example’ with 2 probes:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+start_ephys_session example 2
+
+
+
+
+

Copy command

+
+

Usage

+

To initiate the data transfer from the local server to the remote server, open a terminal and type.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag ephys
+
+
+

The transfer local and remote directories are set in the +iblrig/settings/iblrig_settings.py file.

+
+
+
+

Look at the raw data

+

This will launch the viewephys GUI, you can then use file -> open and navigate +to open the raw data file you wish to display.

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+viewephys
+
+
+Alternative text +

More information on the viewephys package can be found at: https://github.com/int-brain-lab/viewephys

+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/usage_video.html b/usage_video.html new file mode 100644 index 000000000..29a2a15a1 --- /dev/null +++ b/usage_video.html @@ -0,0 +1,203 @@ + + + + + + + Video acquisition computer — iblrig 8.24.1 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Video acquisition computer

+

Video can be run on a separate computer, which is recommended when recording multiple cameras.

+
+

Setup

+
+

Installing drivers

+

Both spinnaker and pyspin must be installed before running an experiment:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+install_spinnaker
+install_pyspin
+
+
+
+
+

Settings config

+

The camera acquisition is configured by parameters in the ‘device_cameras’ key of the hardware_settings.yaml file. +Below is an overview of the parameters:

+
device_cameras:
+  # The name of the configuration. This is passed to the CLI.
+  default:
+    # This is required: the Bonsai workflows to be called by the CLI script.
+    BONSAI_WORKFLOW:
+      # Optional setup (e.g. alignment) workflow
+      setup: devices/camera_setup/EphysRig_SetupCameras.bonsai
+      # Required workflow to be called when the experiment starts
+      recording: devices/camera_recordings/TrainingRig_SaveVideo_TrainingTasks.bonsai
+    # Camera #1 name
+    left:
+      # Required camera device index (assigned in driver software)
+      INDEX: 1
+      # Optional expected frame height. Actual resolution should be set in the driver software.
+      HEIGHT: 1024
+      # Optional expected frame width. This is simply used in QC.
+      WIDTH: 1280
+      # Optional expected frame rate (Hz). This is simply used in QC.
+      FPS: 30
+
+
+

Multiple configurations can be added, e.g. ‘default’, ‘training’, ‘ephys’, etc. and within each, multiple cameras +can be added, e.g. ‘left’, ‘right’, ‘body’, etc. Each configuration requires a BONSAI_WORKFLOW: recording key; +each camera requires an INDEX key.

+
+
+
+

Starting a task

+

Below shows how to start the cameras for the subject ‘example’ with configuration ‘default’:

+
cd C:\iblrigv8\
+venv\scripts\Activate.ps1
+start_video_session example default
+
+
+
+
+

Copy command

+
+

Usage

+

To initiate the data transfer from the local server to the remote server, open a terminal and type.

+
C:\iblrigv8\venv\scripts\Activate.ps1
+transfer_data --tag video
+
+
+

The transfer local and remote directories are set in the +iblrig/settings/iblrig_settings.py file.

+
+
+
+ + +
+
+
+ +
+ +
+

© Copyright 2018 – 2024 International Brain Laboratory.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file