deer-agent-framework 0.0__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.
Files changed (52) hide show
  1. deer/__init__.py +36 -0
  2. deer/builtins/__init__.py +7 -0
  3. deer/builtins/python_manager/agent.py +29 -0
  4. deer/builtins/python_manager/tools.py +54 -0
  5. deer/core/__init__.py +1 -0
  6. deer/core/agent.py +463 -0
  7. deer/core/ui.py +31 -0
  8. deer/drivers/__init__.py +66 -0
  9. deer/drivers/base_driver.py +56 -0
  10. deer/drivers/gemini_driver.py +62 -0
  11. deer/drivers/ollama_driver.py +69 -0
  12. deer/executor/__init__.py +1 -0
  13. deer/executor/executor.py +168 -0
  14. deer/executor/logic.py +75 -0
  15. deer/executor/logic_secure.py +102 -0
  16. deer/main.py +71 -0
  17. deer/planner/__init__.py +1 -0
  18. deer/planner/planner.py +71 -0
  19. deer/prompts/__init__.py +6 -0
  20. deer/prompts/error_explain.py +30 -0
  21. deer/prompts/goal_improvement.py +65 -0
  22. deer/prompts/goal_validation.py +31 -0
  23. deer/prompts/humanizer.py +20 -0
  24. deer/prompts/planner.py +92 -0
  25. deer/prompts/response_improvement.py +23 -0
  26. deer/schema/__init__.py +2 -0
  27. deer/schema/io.py +40 -0
  28. deer/schema/plan.py +75 -0
  29. deer/tools/__init__.py +4 -0
  30. deer/tools/base.py +141 -0
  31. deer/tools/builtin/__init__.py +3 -0
  32. deer/tools/builtin/file_manager.py +136 -0
  33. deer/tools/builtin/git_manager.py +67 -0
  34. deer/tools/builtin/search_manager.py +123 -0
  35. deer/tools/decorators.py +127 -0
  36. deer/tools/registry.py +114 -0
  37. deer/tracing/__init__.py +2 -0
  38. deer/tracing/logging_config.py +20 -0
  39. deer/tracing/store.py +21 -0
  40. deer/utils/__init__.py +0 -0
  41. deer/utils/console.py +11 -0
  42. deer/utils/plots/__init__.py +7 -0
  43. deer/utils/plots/plot_traces.py +1034 -0
  44. deer/validator/__init__.py +1 -0
  45. deer/validator/plan_validator.py +23 -0
  46. deer/validator/rules.py +98 -0
  47. deer_agent_framework-0.0.dist-info/METADATA +163 -0
  48. deer_agent_framework-0.0.dist-info/RECORD +52 -0
  49. deer_agent_framework-0.0.dist-info/WHEEL +5 -0
  50. deer_agent_framework-0.0.dist-info/entry_points.txt +2 -0
  51. deer_agent_framework-0.0.dist-info/licenses/LICENSE +24 -0
  52. deer_agent_framework-0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ from .plan_validator import PlanValidator
@@ -0,0 +1,23 @@
1
+ from typing import Callable
2
+ from deer.schema.plan import Plan
3
+ from deer.tools.registry import ToolRegistry
4
+ from .rules import Rules
5
+
6
+ Rule = Callable[[Plan], None]
7
+
8
+
9
+ class PlanValidator:
10
+ """Validador de planes que compone múltiples reglas.
11
+
12
+ Uso:
13
+ validator = PlanValidator(registry)
14
+ validator.validate(plan)
15
+ """
16
+
17
+ def __init__(self, registry: ToolRegistry) -> None:
18
+ self.registry = registry
19
+
20
+ def validate(self, plan: Plan) -> None:
21
+
22
+ rules = Rules(plan, self.registry)
23
+ rules.validate()
@@ -0,0 +1,98 @@
1
+ import re
2
+ from typing import Set
3
+ import inspect
4
+ import logging
5
+
6
+ from deer.schema.plan import Plan
7
+ from deer.tools.registry import ToolRegistry
8
+
9
+ logger = logging.getLogger("DEER")
10
+
11
+
12
+ class Rules:
13
+ """Mandatory validation rules for NOMOS executable plans."""
14
+
15
+ def __init__(self, plan: Plan, registry: ToolRegistry) -> None:
16
+ self.plan = plan
17
+ self.registry = registry
18
+
19
+ def validate(self) -> None:
20
+ """Dynamically discovers and executes all methods prefixed with 'check_'."""
21
+ checkers = inspect.getmembers(self, predicate=inspect.ismethod)
22
+ for name, method in checkers:
23
+ if name.startswith("check_"):
24
+ logger.debug(f"Validating rule: {name}")
25
+ method(self.plan)
26
+
27
+ def check_unique_step_ids(self, plan: Plan) -> None:
28
+ seen: Set[str] = set()
29
+ for s in plan.steps:
30
+ if s.id in seen:
31
+ raise ValueError(f"Duplicate step IDs detected: {s.id}")
32
+ seen.add(s.id)
33
+
34
+ def check_existing_references(self, plan: Plan) -> None:
35
+ ids = {s.id for s in plan.steps}
36
+ for s in plan.steps:
37
+ if s.input_from is not None and s.input_from not in ids:
38
+ raise ValueError(
39
+ f"Step '{s.id}' references an unknown input_from: {s.input_from}"
40
+ )
41
+
42
+ def check_topological_order(self, plan: Plan) -> None:
43
+ """Ensures that input_from (if present) appears earlier in the sequence (preventing cycles/forward references)."""
44
+ index = {s.id: i for i, s in enumerate(plan.steps)}
45
+ for s in plan.steps:
46
+ if s.input_from is None:
47
+ continue
48
+ if index[s.input_from] >= index[s.id]:
49
+ raise ValueError(
50
+ f"Invalid execution order: '{s.id}' depends on '{s.input_from}', which has not been executed yet"
51
+ )
52
+
53
+ def check_tools_registered(self, plan: Plan) -> None:
54
+ for s in plan.steps:
55
+ if s.tool and not self.registry.has(s.tool):
56
+ raise ValueError(f"Tool not found in ToolRegistry: {s.tool}")
57
+
58
+ def check_tools_registered_params(self, plan: Plan) -> None:
59
+ """Ensures tool steps provide exactly the parameters declared by the tool."""
60
+ for s in plan.steps:
61
+ if not s.tool:
62
+ continue
63
+
64
+ tool = self.registry.get(s.tool)
65
+ if not hasattr(tool, "params_type"):
66
+ continue
67
+
68
+ expected_params = set(tool.params_type or {})
69
+ provided_params = set(s.params or {})
70
+
71
+ missing = expected_params - provided_params
72
+ if missing:
73
+ raise ValueError(
74
+ f"Step '{s.id}' is missing required params for tool "
75
+ f"'{s.tool}': {', '.join(sorted(missing))}"
76
+ )
77
+
78
+ unknown = provided_params - expected_params
79
+ if unknown:
80
+ raise ValueError(
81
+ f"Step '{s.id}' provides unknown params for tool "
82
+ f"'{s.tool}': {', '.join(sorted(unknown))}"
83
+ )
84
+
85
+ def check_execution(self, plan: Plan) -> None:
86
+ for s in plan.steps:
87
+ if not s.tool and not s.logic:
88
+ raise ValueError(
89
+ f"Step '{s.id}' is invalid: it must define either a 'tool' or a 'logic' block to be executed."
90
+ )
91
+
92
+ def check_logic_assignment(self, plan: Plan) -> None:
93
+ for s in plan.steps:
94
+ if logic := s.logic:
95
+ if not re.search(r"\bresult\s*=", logic):
96
+ raise ValueError(
97
+ f"Step '{s.id}' has invalid logic: it must assign a value to 'result' (e.g., 'result = ...')."
98
+ )
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: deer-agent-framework
3
+ Version: 0.0
4
+ Summary: DEER - Deterministic Executable Engine for Runtime-agents
5
+ Author: Yeison
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: pydantic>=2.0
10
+ Requires-Dist: rich
11
+ Requires-Dist: prompt_toolkit
12
+ Provides-Extra: debug
13
+ Requires-Dist: matplotlib>=3.10.9; extra == "debug"
14
+ Requires-Dist: pandas>=3.0.3; extra == "debug"
15
+ Requires-Dist: pytest>=9.0.3; extra == "debug"
16
+ Dynamic: license-file
17
+
18
+ # DEER: Deterministic Executable Engine for Runtime Agents
19
+
20
+ ### **Stop building "Vibe-based" Agents. Start Engineering Deterministic Agents.**
21
+
22
+ **DEER** is the first framework designed for building **Deterministic Agents** in production environments where "it usually works" isn't good enough. While other frameworks rely on massive system prompts and probabilistic loops, DEER subordinates LLMs to rigid, code-defined software structures.
23
+
24
+ [![License](https://img.shields.io/badge/license-BSD--2--Clause-blue.svg)](LICENSE)
25
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
26
+
27
+ ---
28
+
29
+ ## Why DEER?
30
+
31
+ Most agent frameworks suffer from **"Prompt Drift"**: you change one word in a system prompt and the whole logic breaks. DEER replaces "vibes" with **Deterministic Agents** powered by **Code Contracts**.
32
+
33
+ * **Logic over Prompts:** Define your **Deterministic Agent**'s behavior in Python, not in a 2000-word text file.
34
+ * **Typed Tooling:** Every tool has a Pydantic-validated input and output. No more "hallucinated" arguments.
35
+ * **Jailed by Design:** Built-in filesystem sandboxing (Jail) ensures your **Deterministic Agent** can't escape its directory.
36
+ * **Verification Loops:** The agent doesn't just "execute"; it validates the result against the original goal using deterministic traces.
37
+
38
+ ---
39
+
40
+ ## The DEER Workflow: Code-First Implementation
41
+
42
+ ### 1. Define your Deterministic Agent's Identity
43
+ Forget about telling the AI to "act like a specialist." Define a high-level `DeterministicAgent` with clear boundaries and a specific tool registry.
44
+
45
+ ```python
46
+ from pathlib import Path
47
+ from deer.core.agent import DeterministicAgent
48
+ from deer.drivers import get_driver_from_parser
49
+ from .tools import registry
50
+
51
+ agent = DeterministicAgent(
52
+ description="Python Architecture Specialist",
53
+ identity=(
54
+ "You are a Principal Python Architect. You possess authoritative expertise "
55
+ "in advanced module resolution and dependency management."
56
+ ),
57
+ driver=get_driver_from_parser(),
58
+ registry=registry,
59
+ jail_path=Path.cwd() / "sandbox", # Strict security boundary
60
+ format_response="markdown",
61
+ max_tries_for_plan=5
62
+ )
63
+
64
+ if __name__ == "__main__":
65
+ agent.repl() # Instant interactive shell
66
+ ```
67
+
68
+ ### 2. Assemble your Tool Registry
69
+ Combine built-in managers (File, Git, Search) into a single, cohesive unit of execution for your **Deterministic Agent**.
70
+
71
+ ```python
72
+ from deer.tools.registry import ToolRegistry
73
+ from deer.tools.builtin import FileManager, GitManager, SearchManager
74
+
75
+ registry = ToolRegistry()
76
+
77
+ # Add specialized capabilities with zero-config
78
+ registry.register(
79
+ FileManager(),
80
+ GitManager(),
81
+ SearchManager(),
82
+ )
83
+ ```
84
+
85
+ ### 3. Create Custom Tools with Pydantic Validation
86
+ Extending your **Deterministic Agent** is as simple as writing a class. The `@tool` decorator automatically generates the JSON schema for the LLM, ensuring perfect compatibility.
87
+
88
+ ```python
89
+ from deer.tools import ToolProvider, tool, Return
90
+
91
+ class MyCustomProvider(ToolProvider):
92
+ @tool(modifies_state=True)
93
+ def deploy_module(self, name: str, version: str) -> Return(status=str, job_id=int):
94
+ """Deploys a specific python module to the internal repo."""
95
+ # Your deterministic logic here
96
+ return {"status": "success", "job_id": 12345}
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Built-in Deterministic Agents
102
+
103
+ The framework includes pre-configured **Deterministic Agents** in the `deer/builtins/` directory. These serve as both ready-to-use tools and reference implementations for building your own specialized architects and managers.
104
+
105
+ ---
106
+
107
+ ## Technical Differentiation
108
+
109
+ | Feature | Traditional Frameworks (LangChain, etc.) | **DEER Deterministic Agents** |
110
+ | :--- | :--- | :--- |
111
+ | **Execution Flow** | Probabilistic (LLM decides next step) | **Deterministic** (Backend-validated Plan) |
112
+ | **Tool Arguments** | Often Hallucinated | **Strictly Typed** (Pydantic Models) |
113
+ | **Security** | None / Manual | **Built-in Jail (Sandbox)** |
114
+ | **Debugging** | Black box / Tricky logs | **Step-by-Step Trace Replay** |
115
+ | **Output** | Raw Text | **Validated & Humanized Data** |
116
+
117
+ ---
118
+
119
+ ## The "Assembly Line" Lifecycle
120
+
121
+ A **Deterministic Agent** in DEER doesn't just "chat". It processes requests through a linear production line:
122
+
123
+ 1. **Refinement:** The **Deterministic Agent** improves the user's goal for technical clarity.
124
+ 2. **Planning:** The agent generates a complete JSON pipeline *before* executing anything.
125
+ 3. **Static Analysis:** The `PlanValidator` checks the plan for cycles or type mismatches.
126
+ 4. **Jailed Execution:** Tools run inside a secure sandbox.
127
+ 5. **Verification:** A secondary "judge" loop confirms the result matches the goal.
128
+
129
+ ---
130
+
131
+ ## Empirical Evidence: Engineering vs. Vibes
132
+
133
+ DEER isn't just a "good idea"—it's a measured engineering framework. Below is the data from **100 consecutive executions** of a complex Python architecture task using the `gemma4:31b` model.
134
+
135
+ ### 1. Planning Determinism
136
+ While traditional agents hallucinate different paths every time, DEER's planning and validation loop ensures high predictability.
137
+
138
+ ![Deterministic Path Frequencies](assets/planification_validation_paths_frequencies.svg)
139
+ *Figure 1: Path frequency distribution. 90% of executions follow the same validated optimal path, ensuring production-grade reliability.*
140
+
141
+ ### 2. Full Trace Introspección
142
+ Every decision, tool call, and validation step is recorded. This allows for deep auditing and performance profiling.
143
+
144
+ ![Trace Step Analysis](assets/planification_validation_paths.svg)
145
+ *Figure 2: Multi-trace step analysis showing the density and consistency of the agent's internal logic across multiple runs.*
146
+
147
+ ---
148
+
149
+ ## Installation
150
+
151
+ ```bash
152
+ pip install git+https://github.com/dunderlab/deer-agent-framework.git
153
+ ```
154
+
155
+ *Requires Python 3.12+ and a valid LLM API Key (Gemini, Ollama, etc.).*
156
+
157
+ ---
158
+
159
+ ## License
160
+ Licensed under the **BSD 2-Clause License**. See [LICENSE](LICENSE) for details.
161
+
162
+ ---
163
+ **Built for developers who trust code, not prompts.**
@@ -0,0 +1,52 @@
1
+ deer/__init__.py,sha256=ifUGd9ihYllSbpPHFXmEOSLbPG9G_6h-Wsfp9NCA4w4,1164
2
+ deer/main.py,sha256=c0wo0gsItnLi7SE5EKR_GVdfiLem1CKBKSCsnhZcl0U,1480
3
+ deer/builtins/__init__.py,sha256=caSlXaz76tSogUhshgd8dmOPaHeBRPVh2qVMeQShAAg,131
4
+ deer/builtins/python_manager/agent.py,sha256=-qclz3mDkh2b-mEZUmgShhbELNSeGFhb9OJsWnuLXqU,1100
5
+ deer/builtins/python_manager/tools.py,sha256=eI5MPebDb7NHMNqseNt4IxzDZhw7lfk4BgwvuIla9ko,1193
6
+ deer/core/__init__.py,sha256=YbWZ-Wn2_sTQf0mrWo2M0XJoo26tiSrmYj5PBKBRO-w,38
7
+ deer/core/agent.py,sha256=Kvm7J-gCiN-E12xrwC7RO00srKUkz78afryLOxldvmY,15482
8
+ deer/core/ui.py,sha256=q-fOzrP1ThPyfe2hfF0j6RMz6cqEtIeLxTQSrpk4094,894
9
+ deer/drivers/__init__.py,sha256=UF0yV7dDwosr1lNO0fhMBBkS4HbClff9QGBhnWaR5Gk,1497
10
+ deer/drivers/base_driver.py,sha256=FUhDQ_CsxfEkJFnNdrdzcVnr7MHI6DAAYD4NQeczZMY,2108
11
+ deer/drivers/gemini_driver.py,sha256=Rr454dbuvckjOlGt8gUeWNC7KtF5aCS-RCR-ltZH1J4,2403
12
+ deer/drivers/ollama_driver.py,sha256=WfQZjyPmOuni1KmkcspifDV9GWf6YYYDyKkrJZj3QZo,2185
13
+ deer/executor/__init__.py,sha256=_esL73v9Gi40xb5N7UGxslIk8yHM6idQlXbzELR7XhA,31
14
+ deer/executor/executor.py,sha256=U91of8bXGhvGyS1XuMS60Vzlro-cH3UP5OVdRb3GVQA,5282
15
+ deer/executor/logic.py,sha256=uvPKyMPM9GqRNFbfnMvIJIJlaBfpSMma0DeS8lWWjg0,2399
16
+ deer/executor/logic_secure.py,sha256=RpkK_LzEMiTF0TEtSE2I8kQwi67VMWeW8n51BPC1VRk,2889
17
+ deer/planner/__init__.py,sha256=ooTZx2QA-6ySaL1JxyDSm3TQyzAhOW5fv2jPDI6iYeA,29
18
+ deer/planner/planner.py,sha256=kwaZYTAhrG948QmylYOPhDWBPzM4I9RkZdAK9p8kfqw,2208
19
+ deer/prompts/__init__.py,sha256=b5X52rjXI7eoqwGyUdz4K6yowKHl9K2BeL3hYJlt6CQ,313
20
+ deer/prompts/error_explain.py,sha256=QWiFzvsjt93E5eQkDv3ZSUOE2_tz7oyd3RTmqHErVN8,1049
21
+ deer/prompts/goal_improvement.py,sha256=_zGCOeToJ730UJUV97s_Yu_Uc-nNJv388UZOL-YzNJI,1611
22
+ deer/prompts/goal_validation.py,sha256=c1s4uO8-oywtyaeArTyOseMDm-PcfTRSeEZPlqYzEL0,1099
23
+ deer/prompts/humanizer.py,sha256=-a427rzJJRLtScINa5KlvvRZvqYjmRs2TtBNSUpW0FM,652
24
+ deer/prompts/planner.py,sha256=0yrJjtTBEhDjAZjZFuEpelxwSqaliXoIdaw0xKAxHyU,4813
25
+ deer/prompts/response_improvement.py,sha256=Vd1AackmULHrM_v-TckKNopLHFa86Lwcv8K3ktxScc4,748
26
+ deer/schema/__init__.py,sha256=hDfzexGlSLnTvgRdmZEVScNymuspgHXSsMXJc549CmE,69
27
+ deer/schema/io.py,sha256=ocWKvwyInrgyyjDB9YPBpA7Zm-JTzLoOvNP4PhH1gmg,976
28
+ deer/schema/plan.py,sha256=Bxn2rDKy8Q_vus7GnRRtwbvYsrjYAgiBrVFYTiy5VH8,2169
29
+ deer/tools/__init__.py,sha256=ZHnRX5jbMKhJLF_ks0BU_hixEqCxMvan--vueakqFsY,135
30
+ deer/tools/base.py,sha256=k1L6FkPVClt-oqagN1fI84Ml_4WKuN_7Q-9iG0xENTk,3970
31
+ deer/tools/decorators.py,sha256=BBmoRS5P1FXuaq8JOSEM2pglLt0u6xbv_XO_ChEizeM,3066
32
+ deer/tools/registry.py,sha256=RSZ1t1fsa2rI_mW3XndfVvyucW2l-Xi41daOL2bFm2U,3312
33
+ deer/tools/builtin/__init__.py,sha256=3Nw4LIQazbQJuWALxifEHUlzHbsf0U4KMNQ9KUX3reE,116
34
+ deer/tools/builtin/file_manager.py,sha256=wnhUzRZQHiopuDZn536injBcZvxQ7yfZIUv0HlmzR4U,4052
35
+ deer/tools/builtin/git_manager.py,sha256=_aZQ-9y_SDecx8d2_inADq6ui2ca3q-wb0XKjlgetVk,2471
36
+ deer/tools/builtin/search_manager.py,sha256=QoRKABwzdC9gF99D9Bd0kYktfvjQ8KVmAgYyHmSROVg,4023
37
+ deer/tracing/__init__.py,sha256=adxrIDXfgwLyNqYRDi5sUfR9WweeYHq93KGBuxMuZWA,77
38
+ deer/tracing/logging_config.py,sha256=Do0r8UCmJEOQJRAAhVrS5myoUEY7clMKf1MWhLVBs-0,560
39
+ deer/tracing/store.py,sha256=GXoUdfikPxTfxaEr2FAw7vb-LzraLLxu_iWCqpnkYus,584
40
+ deer/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ deer/utils/console.py,sha256=RM8G-JXn_6SqrzIc9daLspiU2L5trOr8tFomCYFYLEA,227
42
+ deer/utils/plots/__init__.py,sha256=P7J8wm23suxDDREeZCjxzcD6brxdHP8XNkx3b18Urcw,150
43
+ deer/utils/plots/plot_traces.py,sha256=OJSd__W6z0YpEBx4cTmgUKkodg1GQED0aZvKEcMOwMU,26659
44
+ deer/validator/__init__.py,sha256=9gpKXZuTogJ15PeH97qkR2a2V1A67xfIhJjTqgcpXW4,42
45
+ deer/validator/plan_validator.py,sha256=ymwBzd-HHQNgqqAsycr7K07SCYq6dvi63VMaTsyv8k8,543
46
+ deer/validator/rules.py,sha256=Ir27wqXvG7Ghx7V1PdNXcVgFYQX6YOaXikNXS71dS7A,3761
47
+ deer_agent_framework-0.0.dist-info/licenses/LICENSE,sha256=hOaNvKhAfQsJnPIB8u-MO0-bdaoQkLVO7k_ymroMxKw,1298
48
+ deer_agent_framework-0.0.dist-info/METADATA,sha256=wObx0GEpXTcsIva-zc9hy6JV5WqSXxCxoOkQrAkfO2Y,6530
49
+ deer_agent_framework-0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
50
+ deer_agent_framework-0.0.dist-info/entry_points.txt,sha256=2kDeh5Omj3tcXBKn0osrZR8lrx9pmwq248Ae1QU55Vw,40
51
+ deer_agent_framework-0.0.dist-info/top_level.txt,sha256=qERYun4uXbfcknYL72x6op65NIjQadU1mc8j38-vC74,5
52
+ deer_agent_framework-0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ deer = deer.main:main
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, DunderLab
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ deer