edsl 0.1.36.dev6__py3-none-any.whl → 0.1.37__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- edsl/Base.py +303 -303
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +48 -47
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +855 -804
- edsl/agents/AgentList.py +350 -337
- edsl/agents/Invigilator.py +222 -222
- edsl/agents/InvigilatorBase.py +284 -294
- edsl/agents/PromptConstructor.py +353 -312
- edsl/agents/__init__.py +3 -3
- edsl/agents/descriptors.py +99 -86
- edsl/agents/prompt_helpers.py +129 -129
- edsl/auto/AutoStudy.py +117 -117
- edsl/auto/StageBase.py +230 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +73 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +224 -224
- edsl/base/Base.py +289 -289
- edsl/config.py +149 -149
- edsl/conjure/AgentConstructionMixin.py +160 -152
- edsl/conjure/Conjure.py +62 -62
- edsl/conjure/InputData.py +659 -659
- edsl/conjure/InputDataCSV.py +48 -48
- edsl/conjure/InputDataMixinQuestionStats.py +182 -182
- edsl/conjure/InputDataPyRead.py +91 -91
- edsl/conjure/InputDataSPSS.py +8 -8
- edsl/conjure/InputDataStata.py +8 -8
- edsl/conjure/QuestionOptionMixin.py +76 -76
- edsl/conjure/QuestionTypeMixin.py +23 -23
- edsl/conjure/RawQuestion.py +65 -65
- edsl/conjure/SurveyResponses.py +7 -7
- edsl/conjure/__init__.py +9 -9
- edsl/conjure/naming_utilities.py +263 -263
- edsl/conjure/utilities.py +201 -201
- edsl/conversation/Conversation.py +290 -238
- edsl/conversation/car_buying.py +58 -58
- edsl/conversation/chips.py +95 -0
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +958 -849
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +527 -527
- edsl/data/CacheEntry.py +228 -228
- edsl/data/CacheHandler.py +149 -149
- edsl/data/RemoteCacheSync.py +97 -84
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +4 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +73 -73
- edsl/enums.py +173 -173
- edsl/exceptions/BaseException.py +21 -0
- edsl/exceptions/__init__.py +54 -50
- edsl/exceptions/agents.py +38 -40
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +91 -91
- edsl/exceptions/results.py +29 -26
- edsl/exceptions/scenarios.py +22 -0
- edsl/exceptions/surveys.py +37 -34
- edsl/inference_services/AnthropicService.py +87 -87
- edsl/inference_services/AwsBedrock.py +120 -115
- edsl/inference_services/AzureAI.py +217 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +156 -156
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +147 -147
- edsl/inference_services/InferenceServicesCollection.py +97 -72
- edsl/inference_services/MistralAIService.py +123 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +224 -224
- edsl/inference_services/TestService.py +89 -89
- edsl/inference_services/TogetherAIService.py +170 -170
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +39 -39
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/Answers.py +56 -56
- edsl/jobs/Jobs.py +1347 -1112
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/buckets/BucketCollection.py +63 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +248 -248
- edsl/jobs/interviews/Interview.py +661 -651
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -182
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/runners/JobsRunnerAsyncio.py +338 -337
- edsl/jobs/runners/JobsRunnerStatus.py +332 -332
- edsl/jobs/tasks/QuestionTaskCreator.py +242 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +442 -441
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +163 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/KeyLookup.py +30 -0
- edsl/language_models/LanguageModel.py +706 -718
- edsl/language_models/ModelList.py +102 -102
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/__init__.py +3 -2
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/registry.py +137 -137
- edsl/language_models/repair.py +156 -156
- edsl/language_models/unused/ReplicateBase.py +83 -83
- edsl/language_models/utilities.py +64 -64
- edsl/notebooks/Notebook.py +259 -259
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +357 -358
- edsl/prompts/__init__.py +2 -2
- edsl/questions/AnswerValidatorMixin.py +289 -289
- edsl/questions/QuestionBase.py +656 -616
- edsl/questions/QuestionBaseGenMixin.py +161 -161
- edsl/questions/QuestionBasePromptsMixin.py +234 -266
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +183 -183
- edsl/questions/QuestionFreeText.py +114 -113
- edsl/questions/QuestionFunctional.py +159 -159
- edsl/questions/QuestionList.py +231 -231
- edsl/questions/QuestionMultipleChoice.py +286 -286
- edsl/questions/QuestionNumerical.py +153 -153
- edsl/questions/QuestionRank.py +324 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/RegisterQuestionsMeta.py +71 -71
- edsl/questions/ResponseValidatorABC.py +174 -174
- edsl/questions/SimpleAskMixin.py +73 -73
- edsl/questions/__init__.py +26 -26
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +87 -87
- edsl/questions/derived/QuestionTopK.py +91 -91
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +413 -418
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/question_registry.py +147 -147
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/Dataset.py +293 -293
- edsl/results/DatasetExportMixin.py +717 -693
- edsl/results/DatasetTree.py +145 -145
- edsl/results/Result.py +450 -433
- edsl/results/Results.py +1071 -1158
- edsl/results/ResultsDBMixin.py +238 -238
- edsl/results/ResultsExportMixin.py +43 -43
- edsl/results/ResultsFetchMixin.py +33 -33
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/ResultsToolsMixin.py +98 -98
- edsl/results/Selector.py +135 -118
- edsl/results/__init__.py +2 -2
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/FileStore.py +458 -443
- edsl/scenarios/Scenario.py +546 -507
- edsl/scenarios/ScenarioHtmlMixin.py +64 -59
- edsl/scenarios/ScenarioList.py +1112 -1101
- edsl/scenarios/ScenarioListExportMixin.py +52 -52
- edsl/scenarios/ScenarioListPdfMixin.py +261 -261
- edsl/scenarios/__init__.py +4 -2
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +528 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +330 -324
- edsl/surveys/RuleCollection.py +387 -387
- edsl/surveys/Survey.py +1795 -1772
- edsl/surveys/SurveyCSS.py +261 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/SurveyFlowVisualizationMixin.py +121 -121
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/__init__.py +3 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +56 -56
- edsl/surveys/instructions/ChangeInstruction.py +47 -47
- edsl/surveys/instructions/Instruction.py +51 -51
- edsl/surveys/instructions/InstructionCollection.py +77 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +9 -9
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +409 -391
- {edsl-0.1.36.dev6.dist-info → edsl-0.1.37.dist-info}/LICENSE +21 -21
- {edsl-0.1.36.dev6.dist-info → edsl-0.1.37.dist-info}/METADATA +1 -1
- edsl-0.1.37.dist-info/RECORD +283 -0
- edsl-0.1.36.dev6.dist-info/RECORD +0 -279
- {edsl-0.1.36.dev6.dist-info → edsl-0.1.37.dist-info}/WHEEL +0 -0
@@ -1,28 +1,28 @@
|
|
1
|
-
import json
|
2
|
-
from edsl.utilities.utilities import valid_json
|
3
|
-
|
4
|
-
|
5
|
-
def extract_json_from_string(s):
|
6
|
-
"""Extract a JSON string from a string."""
|
7
|
-
# Find the first occurrence of '{'
|
8
|
-
start_idx = s.find("{")
|
9
|
-
# Find the last occurrence of '}'
|
10
|
-
end_idx = s.rfind("}")
|
11
|
-
# If both '{' and '}' are found in the string
|
12
|
-
if start_idx != -1 and end_idx != -1 and start_idx < end_idx:
|
13
|
-
# Extract the substring from start_idx to end_idx (inclusive)
|
14
|
-
json_str = s[start_idx : end_idx + 1]
|
15
|
-
try:
|
16
|
-
return json.loads(json_str)
|
17
|
-
except json.JSONDecodeError:
|
18
|
-
raise ValueError("Invalid JSON string")
|
19
|
-
else:
|
20
|
-
raise ValueError("No JSON object found in string")
|
21
|
-
|
22
|
-
|
23
|
-
if __name__ == "__main__":
|
24
|
-
text = (
|
25
|
-
'Sure - here is some JSON { "key": "value", "number": 123, "array": [1, 2, 3] }'
|
26
|
-
)
|
27
|
-
extracted_json = extract_json_from_string(text)
|
28
|
-
d = extracted_json
|
1
|
+
import json
|
2
|
+
from edsl.utilities.utilities import valid_json
|
3
|
+
|
4
|
+
|
5
|
+
def extract_json_from_string(s):
|
6
|
+
"""Extract a JSON string from a string."""
|
7
|
+
# Find the first occurrence of '{'
|
8
|
+
start_idx = s.find("{")
|
9
|
+
# Find the last occurrence of '}'
|
10
|
+
end_idx = s.rfind("}")
|
11
|
+
# If both '{' and '}' are found in the string
|
12
|
+
if start_idx != -1 and end_idx != -1 and start_idx < end_idx:
|
13
|
+
# Extract the substring from start_idx to end_idx (inclusive)
|
14
|
+
json_str = s[start_idx : end_idx + 1]
|
15
|
+
try:
|
16
|
+
return json.loads(json_str)
|
17
|
+
except json.JSONDecodeError:
|
18
|
+
raise ValueError("Invalid JSON string")
|
19
|
+
else:
|
20
|
+
raise ValueError("No JSON object found in string")
|
21
|
+
|
22
|
+
|
23
|
+
if __name__ == "__main__":
|
24
|
+
text = (
|
25
|
+
'Sure - here is some JSON { "key": "value", "number": 123, "array": [1, 2, 3] }'
|
26
|
+
)
|
27
|
+
extracted_json = extract_json_from_string(text)
|
28
|
+
d = extracted_json
|
@@ -1,70 +1,70 @@
|
|
1
|
-
from RestrictedPython import compile_restricted, safe_globals
|
2
|
-
from RestrictedPython.Guards import (
|
3
|
-
safe_builtins,
|
4
|
-
full_write_guard,
|
5
|
-
guarded_iter_unpack_sequence,
|
6
|
-
)
|
7
|
-
|
8
|
-
|
9
|
-
def guarded_iter(obj, allowed_types=(list, tuple, set, dict, range)):
|
10
|
-
"""Ensures iteration is only performed on safe, allowable types."""
|
11
|
-
if not isinstance(obj, allowed_types):
|
12
|
-
raise TypeError(f"Iteration over {type(obj).__name__} not allowed.")
|
13
|
-
return iter(obj)
|
14
|
-
|
15
|
-
|
16
|
-
class FunctionAForbiddenAttributeException(Exception):
|
17
|
-
"""Exception for errors during function execution when forbidden key is used."""
|
18
|
-
|
19
|
-
|
20
|
-
def default_guarded_getitem(ob, key):
|
21
|
-
sensitive_python_keys = [
|
22
|
-
"__dict__",
|
23
|
-
"__class__",
|
24
|
-
"__module__",
|
25
|
-
"__bases__",
|
26
|
-
"__mro__",
|
27
|
-
"__subclasses__",
|
28
|
-
"__func__",
|
29
|
-
"__self__",
|
30
|
-
"__closure__",
|
31
|
-
"__code__",
|
32
|
-
"__globals__",
|
33
|
-
"__call__",
|
34
|
-
"__getattr__",
|
35
|
-
"__getattribute__",
|
36
|
-
"__delattr__",
|
37
|
-
"__setattr__",
|
38
|
-
]
|
39
|
-
if key in sensitive_python_keys:
|
40
|
-
raise FunctionAForbiddenAttributeException(
|
41
|
-
f"Access denied for attribute: {key}"
|
42
|
-
)
|
43
|
-
|
44
|
-
return ob.get(key)
|
45
|
-
|
46
|
-
|
47
|
-
def create_restricted_function(function_name, source_code, loop_activated=True):
|
48
|
-
"""Activate the function using RestrictedPython with basic restrictions."""
|
49
|
-
safe_env = safe_globals.copy()
|
50
|
-
safe_env["__builtins__"] = {**safe_builtins}
|
51
|
-
safe_env["_getitem_"] = default_guarded_getitem
|
52
|
-
|
53
|
-
if loop_activated:
|
54
|
-
safe_env["_getiter_"] = guarded_iter
|
55
|
-
safe_env["_iter_unpack_sequence_"] = guarded_iter_unpack_sequence
|
56
|
-
|
57
|
-
tmp_source_code = source_code.split("def ")
|
58
|
-
if len(tmp_source_code) >= 2:
|
59
|
-
source_code = "def " + tmp_source_code[1]
|
60
|
-
|
61
|
-
byte_code = compile_restricted(source_code, "<string>", "exec")
|
62
|
-
loc = {}
|
63
|
-
try:
|
64
|
-
exec(byte_code, safe_env, loc)
|
65
|
-
func = loc[function_name]
|
66
|
-
except Exception as e:
|
67
|
-
print("Creating restricted function error:", e)
|
68
|
-
raise e
|
69
|
-
|
70
|
-
return func
|
1
|
+
from RestrictedPython import compile_restricted, safe_globals
|
2
|
+
from RestrictedPython.Guards import (
|
3
|
+
safe_builtins,
|
4
|
+
full_write_guard,
|
5
|
+
guarded_iter_unpack_sequence,
|
6
|
+
)
|
7
|
+
|
8
|
+
|
9
|
+
def guarded_iter(obj, allowed_types=(list, tuple, set, dict, range)):
|
10
|
+
"""Ensures iteration is only performed on safe, allowable types."""
|
11
|
+
if not isinstance(obj, allowed_types):
|
12
|
+
raise TypeError(f"Iteration over {type(obj).__name__} not allowed.")
|
13
|
+
return iter(obj)
|
14
|
+
|
15
|
+
|
16
|
+
class FunctionAForbiddenAttributeException(Exception):
|
17
|
+
"""Exception for errors during function execution when forbidden key is used."""
|
18
|
+
|
19
|
+
|
20
|
+
def default_guarded_getitem(ob, key):
|
21
|
+
sensitive_python_keys = [
|
22
|
+
"__dict__",
|
23
|
+
"__class__",
|
24
|
+
"__module__",
|
25
|
+
"__bases__",
|
26
|
+
"__mro__",
|
27
|
+
"__subclasses__",
|
28
|
+
"__func__",
|
29
|
+
"__self__",
|
30
|
+
"__closure__",
|
31
|
+
"__code__",
|
32
|
+
"__globals__",
|
33
|
+
"__call__",
|
34
|
+
"__getattr__",
|
35
|
+
"__getattribute__",
|
36
|
+
"__delattr__",
|
37
|
+
"__setattr__",
|
38
|
+
]
|
39
|
+
if key in sensitive_python_keys:
|
40
|
+
raise FunctionAForbiddenAttributeException(
|
41
|
+
f"Access denied for attribute: {key}"
|
42
|
+
)
|
43
|
+
|
44
|
+
return ob.get(key)
|
45
|
+
|
46
|
+
|
47
|
+
def create_restricted_function(function_name, source_code, loop_activated=True):
|
48
|
+
"""Activate the function using RestrictedPython with basic restrictions."""
|
49
|
+
safe_env = safe_globals.copy()
|
50
|
+
safe_env["__builtins__"] = {**safe_builtins}
|
51
|
+
safe_env["_getitem_"] = default_guarded_getitem
|
52
|
+
|
53
|
+
if loop_activated:
|
54
|
+
safe_env["_getiter_"] = guarded_iter
|
55
|
+
safe_env["_iter_unpack_sequence_"] = guarded_iter_unpack_sequence
|
56
|
+
|
57
|
+
tmp_source_code = source_code.split("def ")
|
58
|
+
if len(tmp_source_code) >= 2:
|
59
|
+
source_code = "def " + tmp_source_code[1]
|
60
|
+
|
61
|
+
byte_code = compile_restricted(source_code, "<string>", "exec")
|
62
|
+
loc = {}
|
63
|
+
try:
|
64
|
+
exec(byte_code, safe_env, loc)
|
65
|
+
func = loc[function_name]
|
66
|
+
except Exception as e:
|
67
|
+
print("Creating restricted function error:", e)
|
68
|
+
raise e
|
69
|
+
|
70
|
+
return func
|