convert_sdk 1.0.0

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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +191 -0
  4. data/.yardopts +16 -0
  5. data/CONTRIBUTING.md +131 -0
  6. data/LICENSE +201 -0
  7. data/README.md +183 -0
  8. data/RELEASE.md +313 -0
  9. data/Rakefile +16 -0
  10. data/convert_sdk.gemspec +50 -0
  11. data/lib/convert_sdk/api_manager.rb +288 -0
  12. data/lib/convert_sdk/background_timer.rb +129 -0
  13. data/lib/convert_sdk/bucketed_feature.rb +35 -0
  14. data/lib/convert_sdk/bucketed_variation.rb +43 -0
  15. data/lib/convert_sdk/bucketing_manager.rb +134 -0
  16. data/lib/convert_sdk/client.rb +417 -0
  17. data/lib/convert_sdk/comparisons.rb +257 -0
  18. data/lib/convert_sdk/config.rb +214 -0
  19. data/lib/convert_sdk/config_validator.rb +127 -0
  20. data/lib/convert_sdk/context.rb +618 -0
  21. data/lib/convert_sdk/data_manager.rb +897 -0
  22. data/lib/convert_sdk/data_store_manager.rb +185 -0
  23. data/lib/convert_sdk/enums/bucketing_error.rb +18 -0
  24. data/lib/convert_sdk/enums/feature_status.rb +13 -0
  25. data/lib/convert_sdk/enums/goal_data_key.rb +62 -0
  26. data/lib/convert_sdk/enums/log_level.rb +22 -0
  27. data/lib/convert_sdk/enums/rule_error.rb +19 -0
  28. data/lib/convert_sdk/enums/system_events.rb +29 -0
  29. data/lib/convert_sdk/event_manager.rb +125 -0
  30. data/lib/convert_sdk/experience_manager.rb +69 -0
  31. data/lib/convert_sdk/feature_manager.rb +367 -0
  32. data/lib/convert_sdk/fork_guard.rb +144 -0
  33. data/lib/convert_sdk/http_client.rb +198 -0
  34. data/lib/convert_sdk/log_manager.rb +168 -0
  35. data/lib/convert_sdk/murmur_hash3.rb +129 -0
  36. data/lib/convert_sdk/redactor.rb +93 -0
  37. data/lib/convert_sdk/rule_manager.rb +242 -0
  38. data/lib/convert_sdk/segments_manager.rb +241 -0
  39. data/lib/convert_sdk/sentinel.rb +57 -0
  40. data/lib/convert_sdk/stores/memory_store.rb +55 -0
  41. data/lib/convert_sdk/stores/redis_store.rb +126 -0
  42. data/lib/convert_sdk/version.rb +14 -0
  43. data/lib/convert_sdk/visitors_queue.rb +190 -0
  44. data/lib/convert_sdk.rb +218 -0
  45. data/scripts/check-generated-rbs-header.sh +41 -0
  46. data/steep/config_contract_probe.rb +154 -0
  47. metadata +93 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 16cc235aa36baea77098bf6d47a5d479e840ca95a416b36b87f8f178b95895c1
4
+ data.tar.gz: 1354d6d78384ebea2f6b187ae601da34e7090de152fc6ca4fa95480e406c04a0
5
+ SHA512:
6
+ metadata.gz: 5fc43abd0fbf174055ef97a00c3c983f232287f886151990931f2635a733fcd0a626e1b35a7f7ef564b2953bcc3cee32b6fe7cb96a9e9ba7dce40b5dfc2e7ae7
7
+ data.tar.gz: 74e704ae66077b55a6e92a008a44933190208f8b3caaacefbea041801b4e9bfe8e8498f082205bfa71b4901834ed9cca2ce5d3e80b5e317848e4fc4a2b925e6e
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,191 @@
1
+ plugins:
2
+ - rubocop-performance
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.1
6
+ NewCops: enable
7
+ SuggestExtensions: false
8
+ Exclude:
9
+ - "bin/**/*"
10
+ - "vendor/**/*"
11
+ # RBS signature files are not Ruby; exclude from all cops.
12
+ - "**/*.rbs"
13
+ # The demo Rails app (Story 5.2) is an APP, not the gem's lib — it lives
14
+ # under demo/ purely to exercise the SDK end-to-end under a real Puma cluster.
15
+ # It must NOT enter the gem's quality gates (RuboCop here, SimpleCov coverage,
16
+ # RBS/Steep typing): its Rails-idiomatic style, its smoke script, and its
17
+ # boot files follow different conventions and would pollute the gem's offense
18
+ # count and coverage %. The gemspec already excludes every demo/ path from the
19
+ # package; this keeps the LINT gate equally clean. (SimpleCov tracks only
20
+ # lib/ — see spec/spec_helper.rb — so the demo never enters coverage; RBS/Steep
21
+ # only check sig/ against lib/, never demo/.)
22
+ - "demo/**/*"
23
+
24
+ # Every .rb file MUST start with the frozen-string-literal magic comment.
25
+ Style/FrozenStringLiteralComment:
26
+ Enabled: true
27
+ EnforcedStyle: always
28
+
29
+ Style/StringLiterals:
30
+ Enabled: true
31
+ EnforcedStyle: double_quotes
32
+
33
+ Style/StringLiteralsInInterpolation:
34
+ Enabled: true
35
+ EnforcedStyle: double_quotes
36
+
37
+ Layout/LineLength:
38
+ Max: 120
39
+
40
+ # RBS inline type annotations (`#: Type`) are deliberately written without a
41
+ # space after `#` — that exact form is what Steep parses. The hardened HTTP
42
+ # port (Story 1.5) uses them to type empty-literal seams (`{} #: Hash[...]`)
43
+ # at the single Net::HTTP site. Allow the RBS-inline form for this cop.
44
+ Layout/LeadingCommentSpace:
45
+ AllowRBSInlineAnnotation: true
46
+
47
+ # Specs use long descriptive blocks; the default 25-line block limit is noise
48
+ # for RSpec example groups and the SimpleCov config block in spec_helper.
49
+ Metrics/BlockLength:
50
+ Exclude:
51
+ - "spec/**/*"
52
+ - "*.gemspec"
53
+ - "Rakefile"
54
+ - "spec/spec_helper.rb"
55
+
56
+ Metrics/MethodLength:
57
+ Max: 20
58
+
59
+ # The Client and DataManager are the two files Story 2.7's config-caching /
60
+ # background-refresh / lazy-TTL feature extends — the architecture mandates "no
61
+ # new lib files" for that story (refresh logic in the Client, snapshot + TTL
62
+ # bookkeeping in the DataManager), so the cohesive feature surface lands inside
63
+ # these two existing classes rather than being split across new files. The
64
+ # resulting length is a deliberate architecture decision, not unmanaged growth.
65
+ # RuleManager (Story 2.10) is added on the same principle: the OR->AND->OR_WHEN
66
+ # walk levels + leaf evaluation + validation are one cohesive unit mirroring the
67
+ # JS rule-manager.ts class — length is the walk surface, not unmanaged growth.
68
+ # Context (Story 2.11) joins for the same reason: the per-visitor public API
69
+ # (create/attributes/lookups from 2.8 + run_experience(s) decision entry points)
70
+ # is one cohesive surface mirroring the JS context.ts class — the orchestration
71
+ # itself lives in DataManager/ExperienceManager, Context just wires the entry
72
+ # points, fires the lifecycle event, and holds the never-crash boundary.
73
+ Metrics/ClassLength:
74
+ Exclude:
75
+ - "lib/convert_sdk/client.rb"
76
+ - "lib/convert_sdk/data_manager.rb"
77
+ - "lib/convert_sdk/rule_manager.rb"
78
+ - "lib/convert_sdk/context.rb"
79
+ # FeatureManager (Story 3.1) ports feature-manager.ts (the run_feature /
80
+ # run_features resolution surface) PLUS the castType truth table
81
+ # (types-utils.ts). The two cohesive JS modules it mirrors are the unit; the
82
+ # length reflects the ported reference surface, not unmanaged growth (same
83
+ # rationale as the DataManager/RuleManager feature surfaces above).
84
+ - "lib/convert_sdk/feature_manager.rb"
85
+
86
+ # The Client (Story 2.5) is wired by explicit constructor injection of its six
87
+ # collaborator managers (config, log, http, data-store, event, data) — the
88
+ # architecture mandates constructor injection throughout with no globals or
89
+ # singletons, so each dependency is a named keyword argument rather than being
90
+ # hidden inside an options bag. The Context (Story 2.8) follows the same
91
+ # injection contract and adds the two per-visitor values it binds (visitor_id +
92
+ # attributes) on top of its five injected managers. Story 2.11 grows the
93
+ # injection surface again: the DataManager gains its decision-flow collaborators
94
+ # (bucketing_manager, rule_manager, account/project resolvers) and the Context
95
+ # gains the experience_manager. Because every one of these is a NAMED keyword
96
+ # argument (self-documenting at the call site — the readability problem the cop
97
+ # guards against applies to positional lists, not keyword injection), keyword
98
+ # args are excluded from the count; the positional limit stays at 7.
99
+ Metrics/ParameterLists:
100
+ Max: 7
101
+ CountKeywordArgs: false
102
+
103
+ # get_visitor_data / get_config_entity (Story 2.8) are FROZEN public-API parity
104
+ # names mirroring the JS SDK surface (getVisitorData/getConfigEntity,
105
+ # context.ts:495,549). The get_ prefix is mandated by the cross-SDK naming
106
+ # contract, not an accessor-naming slip, so the cop is disabled for the Context.
107
+ Naming/AccessorMethodName:
108
+ Exclude:
109
+ - "lib/convert_sdk/context.rb"
110
+
111
+ # MurmurHash3 uses the canonical algorithm variable names from Austin Appleby's
112
+ # reference implementation (h1 = hash state, k1 = block key). Renaming them would
113
+ # break the line-by-line auditability of the vendored implementation against the
114
+ # reference, so they are explicitly allowed as method parameter names.
115
+ Naming/MethodParameterName:
116
+ AllowedNames:
117
+ - h1
118
+ - k1
119
+
120
+ # The 13 rule operators (Story 2.10) port the JS SDK comparisons.ts signatures
121
+ # verbatim: each takes a trailing positional `negation` boolean so RuleManager
122
+ # can dispatch uniformly across all operators (processor[matching](value, rule
123
+ # value, negation), mirroring rule-manager.ts:299-319). Keyword-izing it would
124
+ # break the uniform positional dispatch and diverge from the JS contract.
125
+ Style/OptionalBooleanParameter:
126
+ Exclude:
127
+ - "lib/convert_sdk/comparisons.rb"
128
+
129
+ # is_in / does_not_exist are the snake_case mirrors of the FROZEN wire operator
130
+ # names isIn / doesNotExist (the two-worlds rule for operator dispatch — the
131
+ # dispatch-map keys stay byte-identical to the rule JSON match_type, the Ruby
132
+ # methods underneath are snake_case). is_rule_matched (RuleManager, Story 2.10)
133
+ # is the snake_case mirror of the FROZEN cross-SDK public API name isRuleMatched
134
+ # (rule-manager.ts:99). The predicate-prefix cop would force in?/not_exist?/
135
+ # rule_matched?, breaking those naming contracts.
136
+ Naming/PredicatePrefix:
137
+ Exclude:
138
+ - "lib/convert_sdk/comparisons.rb"
139
+ - "lib/convert_sdk/rule_manager.rb"
140
+
141
+ # custom_dimension_1 .. custom_dimension_5 (Story 4.3) are the snake_case mirrors
142
+ # of the FROZEN wire goal-data keys customDimension1 .. customDimension5
143
+ # (the two-worlds rule — the public track_conversion goal_data: kwarg surface is
144
+ # snake_case symbols, the wire identifiers stay camelCase via GoalDataKey). The
145
+ # trailing digit is part of the cross-SDK key name, not a variable-numbering
146
+ # slip; normalcasing them to custom_dimension1 would break the public contract
147
+ # and the snake↔camel mapping. Allowed as identifiers for this cop.
148
+ Naming/VariableNumber:
149
+ AllowedIdentifiers:
150
+ - custom_dimension_1
151
+ - custom_dimension_2
152
+ - custom_dimension_3
153
+ - custom_dimension_4
154
+ - custom_dimension_5
155
+
156
+ # cast_boolean is one branch of the symmetric cast_* helper family (cast_boolean
157
+ # / cast_integer / cast_float / cast_json) that mirrors the JS castType switch
158
+ # (types-utils.ts:13-54) one-to-one. Only the boolean branch happens to return a
159
+ # bool; renaming it cast_boolean? would break the deliberate one-name-per-cast-
160
+ # branch symmetry (the others return Integer/Float/parsed-JSON, not predicates).
161
+ Naming/PredicateMethod:
162
+ Exclude:
163
+ - "lib/convert_sdk/feature_manager.rb"
164
+
165
+ # Comparisons is a cohesive 13-operator + numeric-helper module; the operator
166
+ # set is the unit, not unmanaged growth. (Mirrors the ClassLength rationale for
167
+ # the Client/DataManager feature surfaces.)
168
+ Metrics/ModuleLength:
169
+ Exclude:
170
+ - "lib/convert_sdk/comparisons.rb"
171
+
172
+ # The frozen value objects (BucketedVariation, BucketedFeature) are declared as
173
+ # explicit `class X < Struct.new(...)` subclasses. This is the form the
174
+ # architecture mandates ("frozen Struct subclass") AND the only form Steep can
175
+ # statically resolve: methods defined in a `Struct.new(...) do ... end` block are
176
+ # mis-attributed by Steep to the enclosing module (Ruby::UndeclaredMethodDefinition),
177
+ # whereas the subclass form attributes #error?/#initialize to the class as the RBS
178
+ # declares. The Style/StructInheritance preference is overridden here for that reason.
179
+ Style/StructInheritance:
180
+ Exclude:
181
+ - "lib/convert_sdk/bucketed_variation.rb"
182
+ - "lib/convert_sdk/bucketed_feature.rb"
183
+ - "lib/convert_sdk/http_client.rb"
184
+
185
+ # The steep/ directory holds the build-time config-contract probe (qs-03). The
186
+ # probe re-opens `module ConvertSdk` as a CI-only utility file (OUTSIDE lib/,
187
+ # never required at runtime). The module is already documented in lib/
188
+ # convert_sdk.rb; the probe re-opening does not warrant a second top-level doc.
189
+ Style/Documentation:
190
+ Exclude:
191
+ - "steep/**/*"
data/.yardopts ADDED
@@ -0,0 +1,16 @@
1
+ --output-dir doc
2
+ --markup markdown
3
+ --protected
4
+ --no-private
5
+ --readme README.md
6
+ --title "Convert Ruby SDK"
7
+ lib/**/*.rb
8
+ -
9
+ CONTRIBUTING.md
10
+ docs/quickstart-rails.md
11
+ docs/quickstart-sidekiq.md
12
+ docs/quickstart-lambda.md
13
+ docs/quickstart-cli.md
14
+ docs/troubleshooting.md
15
+ docs/migrate-from-kameleoon.md
16
+ LICENSE
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,131 @@
1
+ # Contributing to the Convert Ruby SDK
2
+
3
+ Thanks for contributing. This guide covers the dev setup, the conventions CI
4
+ enforces, the test layout, and how releases happen.
5
+
6
+ ## Development setup
7
+
8
+ Requires Ruby ≥ 3.1 (the gem supports CRuby 3.1–3.4 and JRuby).
9
+
10
+ ```sh
11
+ bundle install # install dev/test dependencies
12
+ bundle exec rake # the default task: RSpec + RuboCop
13
+ ```
14
+
15
+ Type checking (RBS + Steep) lives in a separate Gemfile group so the JRuby
16
+ matrix leg can skip the C-extension build:
17
+
18
+ ```sh
19
+ bundle exec rbs -r net-http -r uri -r json -I sig validate # validate RBS signatures
20
+ bundle exec steep check # static type check
21
+ ```
22
+
23
+ The gem has **zero runtime dependencies** by design (stdlib only). Adding a
24
+ runtime dependency is an architecture change, not a routine PR — discuss it
25
+ first. All dev/test gems live in the `Gemfile`.
26
+
27
+ ## Conventions CI enforces
28
+
29
+ The **Quality Checks** workflow (`.github/workflows/qa.yml`) gates every PR:
30
+
31
+ - **RuboCop** — `bundle exec rubocop` must pass (config in `.rubocop.yml`).
32
+ Notably: frozen-string-literal magic comment on every file, double-quoted
33
+ strings, 120-char lines.
34
+ - **RBS + Steep** — signatures in `sig/` must validate and type-check against
35
+ `lib/`.
36
+ - **RSpec** — the full suite runs on the CRuby 3.1–3.4 + JRuby matrix, with
37
+ coverage gates (see below).
38
+ - **Cross-SDK parity** — the 75-vector MurmurHash3 parity suite must pass 100%
39
+ (a byte-identical-bucketing release gate).
40
+ - **Full-chain + gem-smoke + demo fork-smoke** — end-to-end release gates.
41
+
42
+ ### Conventional Commits + squash merge
43
+
44
+ This repo is **squash-merge only**, so the **PR title** becomes the squash commit
45
+ subject — and CI validates it as a [Conventional Commit](https://www.conventionalcommits.org/):
46
+
47
+ ```
48
+ <type>(<scope>)?!?: <description>
49
+ ```
50
+
51
+ Allowed types: `feat`, `fix`, `docs`, `test`, `refactor`, `perf`, `build`, `ci`,
52
+ `chore`. A `feat` or `fix` (or a `!` breaking-change marker) drives the next
53
+ release version (see below), so title accuracy matters.
54
+
55
+ Examples:
56
+
57
+ ```
58
+ feat(context): add run_features bulk evaluation
59
+ fix(api): retain queue on a failed flush POST
60
+ docs(readme): document the sentinel return contract
61
+ ```
62
+
63
+ ### Coverage gates
64
+
65
+ Coverage is single-sourced in `spec/spec_helper.rb` (do not declare thresholds
66
+ elsewhere). The global floor is 85% line coverage; the critical algorithm units
67
+ (Hashing, Bucketing, Rules) require ≥ 95% line **and** branch coverage. Coverage
68
+ runs on CRuby only — the JRuby leg runs the suite without the gate.
69
+
70
+ ## Test layout
71
+
72
+ | Directory | What lives there |
73
+ |-----------|------------------|
74
+ | `spec/unit/` | Per-class unit specs (mock collaborators, isolated logic). |
75
+ | `spec/integration/` | End-to-end specs: `full_chain_spec.rb` (the release-blocking create→decide→track→flush loop), `runtime_recipes_spec.rb` (the runtime-lifecycle recipes the quickstarts are transcribed from), `fork_safety_spec.rb`, `factory_wiring_spec.rb`. |
76
+ | `spec/cross_sdk/` | The cross-SDK MurmurHash3 parity vectors (the byte-identical bucketing proof). |
77
+ | `spec/docs/` | Docs-snippet smoke specs — run the README/quickstart code samples against the real gem so documentation never drifts. |
78
+ | `spec/staging/` | The live-platform suite (runs on schedule/dispatch only, never in PR CI). |
79
+ | `spec/support/` | Shared helpers (e.g. `runtime_recipe_helpers.rb`, which co-locates the recipe wiring snippets the quickstarts ship). |
80
+ | `spec/fixtures/` | Vendored config fixtures (`test-config.json`). |
81
+ | `demo/rails/` | The living Rails example app + fork-safety smoke (an app, not the lib — excluded from gem/RuboCop/coverage gates). |
82
+
83
+ When adding a documented code sample, **copy it from a working spec or the demo**
84
+ and add it to the `spec/docs/` smoke spec — never ship doc-only code that can
85
+ drift from the real gem.
86
+
87
+ ## Testing & verification
88
+
89
+ Run the default gate before opening a PR:
90
+
91
+ ```sh
92
+ bundle exec rake # RSpec + RuboCop — the same pair CI enforces
93
+ ```
94
+
95
+ See the **[Testing wiki page](https://github.com/convertcom/ruby-sdk/wiki/Testing)**
96
+ for the full command reference: individual RSpec invocations, the RBS/Steep type-check
97
+ commands, the cross-SDK parity gate, the full-chain release gate, and the Puma-cluster
98
+ fork smoke. Do not change the coverage configuration — it is single-sourced in
99
+ `spec/spec_helper.rb` (see **Coverage gates** above).
100
+
101
+ ## API documentation (YARD)
102
+
103
+ All public classes and methods are YARD-documented; `@api private` internals are
104
+ excluded from the published docs (`.yardopts` sets `--no-private`). Build the
105
+ docs locally with:
106
+
107
+ ```sh
108
+ bundle exec yard doc # output to doc/
109
+ bundle exec yard stats --list-undoc # audit the public surface
110
+ ```
111
+
112
+ The published docs deploy to [GitHub Pages](https://convertcom.github.io/ruby-sdk)
113
+ on every push to `main` (`.github/workflows/pages.yml`).
114
+
115
+ ## Releases
116
+
117
+ Releases are **fully automated** and run only from `main` — there is **no**
118
+ `rake release` task (it is deliberately absent from the `Rakefile`). The release
119
+ pipeline (semantic-release in `.github/workflows/release.yml`) reads the merged
120
+ Conventional Commit subjects since the last release, computes the next semantic
121
+ version, tags it, and publishes the gem to RubyGems via OIDC Trusted Publishing.
122
+ The changelog is **GitHub Releases** (there is no `CHANGELOG.md` in the repo).
123
+
124
+ You never bump the version or publish manually — write an accurate PR title and
125
+ the pipeline does the rest on merge.
126
+
127
+ See **[RELEASE.md](RELEASE.md)** for the full release runbook: the release chain,
128
+ the Conventional-Commit → version map, one-time repo-admin setup (RubyGems
129
+ trusted-publisher registration, GitHub Pages, branch-protection required checks),
130
+ dry-runs, the first `v1.0.0` release, the fork-PR safeguard, rollback (`gem
131
+ yank`), and troubleshooting.
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.