From 18b36964592bd6f6957560dbbb33d15bd2cb0122 Mon Sep 17 00:00:00 2001
From: stuartc Registry process to query and maintain a list of adaptors available for
writing jobs. Currently it queries NPM for all modules in the Usage Caching By default the results are cached to disk, and will be reused every start. In order to disable or configure caching pass see: The process uses Caching By default the results are cached to disk, and will be reused every start. In order to disable or configure caching pass see: The process uses Timeouts There is a 'general' timeout of 30s, this is used for GenServer calls like
Destructures an NPM style package name into module name and version. Example Destructures an NPM style package name into module name and version. Example Queries the AI assistant with the given content. Returns Example Queries the AI assistant with the given content. Returns Example Perform a DELETE request. See Perform a DELETE request. See Perform a DELETE request. See Perform a DELETE request. See Perform a GET request. See Perform a GET request. See Perform a GET request. See Perform a GET request. See Perform a HEAD request. See Perform a HEAD request. See Perform a HEAD request. See Perform a HEAD request. See Perform a OPTIONS request. See Perform a OPTIONS request. See Perform a OPTIONS request. See Perform a OPTIONS request. See Perform a PATCH request. See Perform a PATCH request. See Perform a PATCH request. See Perform a PATCH request. See Perform a POST request. See Perform a POST request. See Perform a POST request. See Perform a POST request. See Perform a PUT request. See Perform a PUT request. See Perform a PUT request. See Perform a PUT request. See Perform a TRACE request. See Perform a TRACE request. See Perform a TRACE request. See Perform a TRACE request. See The OpenFn CLI returns JSON formatted log lines, which are decoded and added
-to a There are two kinds of output: These are usually for general logging, and debugging. The above is the equivalent of the output of a commandapply_user_email(user, password, attrs)
Examples
-
+iex> apply_user_email(user, "valid password", %{email: ...})
-{:ok, %User{}}role: :superuser
-iex> apply_user_email(user, "invalid password", %{email: ...})
-{:error, %Ecto.Changeset{}}
iex> apply_user_email(user, "valid password", %{email: ...})
+{:ok, %User{}}role: :superuser
+iex> apply_user_email(user, "invalid password", %{email: ...})
+{:error, %Ecto.Changeset{}}
change_scheduled_deletion(user, attrs \\ %{
Examples
-
+iex> change_scheduled_deletion(user)
-%Ecto.Changeset{data: %User{}}
iex> change_scheduled_deletion(user)
+%Ecto.Changeset{data: %User{}}
change_superuser_registration(attrs \\ %{})
Examples
-
+iex> change_superuser_registration(user)
-%Ecto.Changeset{data: %User{}}
iex> change_superuser_registration(user)
+%Ecto.Changeset{data: %User{}}
change_user_email(user, attrs \\ %{})
Examples
-
+iex> change_user_email(user)
-%Ecto.Changeset{data: %User{}}
iex> change_user_email(user)
+%Ecto.Changeset{data: %User{}}
change_user_password(user, attrs \\ %{})
Examples
-
+iex> change_user_password(user)
-%Ecto.Changeset{data: %User{}}
iex> change_user_password(user)
+%Ecto.Changeset{data: %User{}}
change_user_registration(attrs \\ %{})
Examples
-
+iex> change_user_registration(user)
-%Ecto.Changeset{data: %User{}}
iex> change_user_registration(user)
+%Ecto.Changeset{data: %User{}}
delete_token(token)
Examples
-iex> delete_token(token)
-{:ok, %UserToken{}}
+
+iex> delete_token(token)
+{:error, %Ecto.Changeset{}}iex> delete_token(token)
+{:ok, %UserToken{}}
-iex> delete_token(token)
-{:error, %Ecto.Changeset{}}
delete_user(user)
Examples
-iex> delete_user(user)
-{:ok, %User{}}
+
+iex> delete_user(user)
+{:error, %Ecto.Changeset{}}iex> delete_user(user)
+{:ok, %User{}}
-iex> delete_user(user)
-{:error, %Ecto.Changeset{}}
deliver_user_confirmation_instructions(user
Examples
-
iex> deliver_user_confirmation_instructions(user)
-{:ok, %{to: ..., body: ...}}
+
+iex> deliver_user_confirmation_instructions(confirmed_user)
+{:error, :already_confirmed}iex> deliver_user_confirmation_instructions(user)
+{:ok, %{to: ..., body: ...}}
-iex> deliver_user_confirmation_instructions(confirmed_user)
-{:error, :already_confirmed}
deliver_user_reset_password_instructions(us
Examples
-
+iex> deliver_user_reset_password_instructions(user, &Routes.user_reset_password_url(conn, :edit, &1))
-{:ok, %{to: ..., body: ...}}
iex> deliver_user_reset_password_instructions(user, &Routes.user_reset_password_url(conn, :edit, &1))
+{:ok, %{to: ..., body: ...}}
get_preference(user, key)
Examples
-iex> get_preference(user, "editor.orientation")
+
iex> get_preference(user, "editor.orientation")
"vertical"
-iex> get_preference(user, "notifications.enabled")
+iex> get_preference(user, "notifications.enabled")
true
get_token!(id)
Examples
-iex> get_token!(123)
-%UserToken{}
+
@@ -1577,10 +1577,10 @@ iex> get_token!(123)
+%UserToken{}
-iex> get_token!(456)
+iex> get_token!(456)
** (Ecto.NoResultsError)
get_user(id)
Examples
-iex> get_user(123)
-%User{}
+
@@ -1675,10 +1675,10 @@ iex> get_user(123)
+%User{}
-iex> get_user!(456)
+iex> get_user!(456)
nil
get_user_by_email(email)
Examples
-iex> get_user_by_email("foo@example.com")
-%User{}
+
@@ -1707,10 +1707,10 @@ iex> get_user_by_email("foo@example.com")
+%User{}
-iex> get_user_by_email("unknown@example.com")
+iex> get_user_by_email("unknown@example.com")
nil
get_user_by_email_and_password(email, passw
Examples
-
iex> get_user_by_email_and_password("foo@example.com", "correct_password")
-%User{}
+
@@ -1739,10 +1739,10 @@ iex> get_user_by_email_and_password("foo@example.com", "correct_password")
+%User{}
-iex> get_user_by_email_and_password("foo@example.com", "invalid_password")
+iex> get_user_by_email_and_password("foo@example.com", "invalid_password")
nil
get_user_by_reset_password_token(token)
Examples
-iex> get_user_by_reset_password_token("validtoken")
-%User{}
+
@@ -1939,8 +1939,8 @@ iex> get_user_by_reset_password_token("validtoken")
+%User{}
-iex> get_user_by_reset_password_token("invalidtoken")
+iex> get_user_by_reset_password_token("invalidtoken")
nil
list_users()
Examples
-
+iex> list_users()
-[%User{}, ...]
iex> list_users()
+[%User{}, ...]
register_superuser(attrs)
Examples
-iex> register_superuser(%{field: value})
-{:ok, %User{}}
+
+iex> register_superuser(%{field: bad_value})
+{:error, %Ecto.Changeset{}}iex> register_superuser(%{field: value})
+{:ok, %User{}}
-iex> register_superuser(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
register_user(attrs)
Examples
-iex> register_user(%{field: value})
-{:ok, %User{}}
+
+iex> register_user(%{field: bad_value})
+{:error, %Ecto.Changeset{}}iex> register_user(%{field: value})
+{:ok, %User{}}
-iex> register_user(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
request_email_update(user, new_email)
Examples
-iex> request_email_update(user, new_email)
+
iex> request_email_update(user, new_email)
:ok
reset_user_password(user, attrs)
Examples
-iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"})
-{:ok, %User{}}
+
+iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
+{:error, %Ecto.Changeset{}}iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"})
+{:ok, %User{}}
-iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
-{:error, %Ecto.Changeset{}}
update_user_password(user, password, attrs)
Examples
-
iex> update_user_password(user, "valid password", %{password: ...})
-{:ok, %User{}}
+
+iex> update_user_password(user, "invalid password", %{password: ...})
+{:error, %Ecto.Changeset{}}iex> update_user_password(user, "valid password", %{password: ...})
+{:ok, %User{}}
-iex> update_user_password(user, "invalid password", %{password: ...})
-{:error, %Ecto.Changeset{}}
update_user_preference(user, key, value)
Examples
-
iex> update_user_preference(user, "editor.orientation", "vertical")
-{:ok, %User{}}
+
+iex> update_user_preference(user, "notifications.enabled", true)
+{:ok, %User{}}iex> update_user_preference(user, "editor.orientation", "vertical")
+{:ok, %User{}}
-iex> update_user_preference(user, "notifications.enabled", true)
-{:ok, %User{}}
update_user_preferences(user, preferences)<
Examples
-
+iex> update_user_preferences(%User{}, %{"editor.orientaion" => "vertical"})
iex> update_user_preferences(%User{}, %{"editor.orientaion" => "vertical"})
validate_change_user_email(user, params \\
Examples
-
+iex> validate_change_user_email(user, %{"email" => "new@example.com", "current_password" => "secret"})
-%Ecto.Changeset{...}
iex> validate_change_user_email(user, %{"email" => "new@example.com", "current_password" => "secret"})
+%Ecto.Changeset{...}
request(request)
Examples
-request = %HTTPoison.Request{
+
+request(request)request = %HTTPoison.Request{
method: :post,
url: "https://my.website.com",
body: "{\"foo\": 3}",
- headers: [{"Accept", "application/json"}]
-}
+ headers: [{"Accept", "application/json"}]
+}
-request(request)
request(method, url, body \\ "",
Examples
-
+request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
@openfn
organization and
filters out modules that are known not to be adaptors.# Starting the process
-AdaptorRegistry.start_link()
+AdaptorRegistry.start_link()
# Getting a list of all adaptors
-Lightning.AdaptorRegistry.AdaptorRegistry.all()
start_link/1
.:continue
to return before the adaptors have been queried.
+start_link/1
.:continue
to return before the adaptors have been queried.
This does mean that the first call to the process will be delayed until
the handle_continue/2
has finished.all/1
and also internally when the modules are being queried. NPM can
@@ -434,10 +434,10 @@ resolve_package_name(package_name)
-
+iex> resolve_package_name("@openfn/language-salesforce@1.2.3")
-{ "@openfn/language-salesforce", "1.2.3" }
-iex> resolve_package_name("@openfn/language-salesforce")
-{ "@openfn/language-salesforce", nil }
iex> resolve_package_name("@openfn/language-salesforce@1.2.3")
+{ "@openfn/language-salesforce", "1.2.3" }
+iex> resolve_package_name("@openfn/language-salesforce")
+{ "@openfn/language-salesforce", nil }
query(session, content)
-{:ok, session}
if the query was successful, otherwise :error
.
+iex> AiAssistant.query(session, "fn()")
-{:ok, session}
{:ok, session}
if the query was successful, otherwise :error
.iex> AiAssistant.query(session, "fn()")
+{:ok, session}
delete(client, url, opts)
-request/1
or request/2
for options definition.
+delete("/users")
-delete("/users", query: [scope: "admin"])
-delete(client, "/users")
-delete(client, "/users", query: [scope: "admin"])
-delete(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.delete("/users")
+delete("/users", query: [scope: "admin"])
+delete(client, "/users")
+delete(client, "/users", query: [scope: "admin"])
+delete(client, "/users", body: %{name: "Jon"})
delete!(client, url, opts)
-request!/1
or request!/2
for options definition.
+delete!("/users")
-delete!("/users", query: [scope: "admin"])
-delete!(client, "/users")
-delete!(client, "/users", query: [scope: "admin"])
-delete!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.delete!("/users")
+delete!("/users", query: [scope: "admin"])
+delete!(client, "/users")
+delete!(client, "/users", query: [scope: "admin"])
+delete!(client, "/users", body: %{name: "Jon"})
get(client, url, opts)
-request/1
or request/2
for options definition.
+get("/users")
-get("/users", query: [scope: "admin"])
-get(client, "/users")
-get(client, "/users", query: [scope: "admin"])
-get(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.get("/users")
+get("/users", query: [scope: "admin"])
+get(client, "/users")
+get(client, "/users", query: [scope: "admin"])
+get(client, "/users", body: %{name: "Jon"})
get!(client, url, opts)
-request!/1
or request!/2
for options definition.
+get!("/users")
-get!("/users", query: [scope: "admin"])
-get!(client, "/users")
-get!(client, "/users", query: [scope: "admin"])
-get!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.get!("/users")
+get!("/users", query: [scope: "admin"])
+get!(client, "/users")
+get!(client, "/users", query: [scope: "admin"])
+get!(client, "/users", body: %{name: "Jon"})
head(client, url, opts)
-request/1
or request/2
for options definition.
+head("/users")
-head("/users", query: [scope: "admin"])
-head(client, "/users")
-head(client, "/users", query: [scope: "admin"])
-head(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.head("/users")
+head("/users", query: [scope: "admin"])
+head(client, "/users")
+head(client, "/users", query: [scope: "admin"])
+head(client, "/users", body: %{name: "Jon"})
head!(client, url, opts)
-request!/1
or request!/2
for options definition.
+head!("/users")
-head!("/users", query: [scope: "admin"])
-head!(client, "/users")
-head!(client, "/users", query: [scope: "admin"])
-head!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.head!("/users")
+head!("/users", query: [scope: "admin"])
+head!(client, "/users")
+head!(client, "/users", query: [scope: "admin"])
+head!(client, "/users", body: %{name: "Jon"})
options(client, url, opts)
-request/1
or request/2
for options definition.
+options("/users")
-options("/users", query: [scope: "admin"])
-options(client, "/users")
-options(client, "/users", query: [scope: "admin"])
-options(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.options("/users")
+options("/users", query: [scope: "admin"])
+options(client, "/users")
+options(client, "/users", query: [scope: "admin"])
+options(client, "/users", body: %{name: "Jon"})
options!(client, url, opts)
-request!/1
or request!/2
for options definition.
+options!("/users")
-options!("/users", query: [scope: "admin"])
-options!(client, "/users")
-options!(client, "/users", query: [scope: "admin"])
-options!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.options!("/users")
+options!("/users", query: [scope: "admin"])
+options!(client, "/users")
+options!(client, "/users", query: [scope: "admin"])
+options!(client, "/users", body: %{name: "Jon"})
patch(client, url, body, opts)
-request/1
or request/2
for options definition.
+patch("/users", %{name: "Jon"})
-patch("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch(client, "/users", %{name: "Jon"})
-patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request/1
or request/2
for options definition.patch("/users", %{name: "Jon"})
+patch("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch(client, "/users", %{name: "Jon"})
+patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
patch!(client, url, body, opts)
-request!/1
or request!/2
for options definition.
+patch!("/users", %{name: "Jon"})
-patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch!(client, "/users", %{name: "Jon"})
-patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request!/1
or request!/2
for options definition.patch!("/users", %{name: "Jon"})
+patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch!(client, "/users", %{name: "Jon"})
+patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
post(client, url, body, opts)
-request/1
or request/2
for options definition.
+post("/users", %{name: "Jon"})
-post("/users", %{name: "Jon"}, query: [scope: "admin"])
-post(client, "/users", %{name: "Jon"})
-post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request/1
or request/2
for options definition.post("/users", %{name: "Jon"})
+post("/users", %{name: "Jon"}, query: [scope: "admin"])
+post(client, "/users", %{name: "Jon"})
+post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
post!(client, url, body, opts)
-request!/1
or request!/2
for options definition.
+post!("/users", %{name: "Jon"})
-post!("/users", %{name: "Jon"}, query: [scope: "admin"])
-post!(client, "/users", %{name: "Jon"})
-post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request!/1
or request!/2
for options definition.post!("/users", %{name: "Jon"})
+post!("/users", %{name: "Jon"}, query: [scope: "admin"])
+post!(client, "/users", %{name: "Jon"})
+post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
put(client, url, body, opts)
-request/1
or request/2
for options definition.
+put("/users", %{name: "Jon"})
-put("/users", %{name: "Jon"}, query: [scope: "admin"])
-put(client, "/users", %{name: "Jon"})
-put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request/1
or request/2
for options definition.put("/users", %{name: "Jon"})
+put("/users", %{name: "Jon"}, query: [scope: "admin"])
+put(client, "/users", %{name: "Jon"})
+put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
put!(client, url, body, opts)
-request!/1
or request!/2
for options definition.
+put!("/users", %{name: "Jon"})
-put!("/users", %{name: "Jon"}, query: [scope: "admin"])
-put!(client, "/users", %{name: "Jon"})
-put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request!/1
or request!/2
for options definition.put!("/users", %{name: "Jon"})
+put!("/users", %{name: "Jon"}, query: [scope: "admin"])
+put!(client, "/users", %{name: "Jon"})
+put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
request(client \\ %Tesla.Client{}, options)
Examples
-
ExampleApi.request(method: :get, url: "/users/path")
+
+ExampleApi.get("/users/1")
+ExampleApi.post(client, "/users", %{name: "Jon"})ExampleApi.request(method: :get, url: "/users/path")
# use shortcut methods
-ExampleApi.get("/users/1")
-ExampleApi.post(client, "/users", %{name: "Jon"})
trace(client, url, opts)
-request/1
or request/2
for options definition.
+trace("/users")
-trace("/users", query: [scope: "admin"])
-trace(client, "/users")
-trace(client, "/users", query: [scope: "admin"])
-trace(client, "/users", body: %{name: "Jon"})
request/1
or request/2
for options definition.trace("/users")
+trace("/users", query: [scope: "admin"])
+trace(client, "/users")
+trace(client, "/users", query: [scope: "admin"])
+trace(client, "/users", body: %{name: "Jon"})
trace!(client, url, opts)
-request!/1
or request!/2
for options definition.
+trace!("/users")
-trace!("/users", query: [scope: "admin"])
-trace!(client, "/users")
-trace!(client, "/users", query: [scope: "admin"])
-trace!(client, "/users", body: %{name: "Jon"})
request!/1
or request!/2
for options definition.trace!("/users")
+trace!("/users", query: [scope: "admin"])
+trace!(client, "/users")
+trace!(client, "/users", query: [scope: "admin"])
+trace!(client, "/users", body: %{name: "Jon"})
request(request)
Examples
-request = %HTTPoison.Request{
+
+request(request)request = %HTTPoison.Request{
method: :post,
url: "https://my.website.com",
body: "{\"foo\": 3}",
- headers: [{"Accept", "application/json"}]
-}
+ headers: [{"Accept", "application/json"}]
+}
-request(request)
request(method, url, body \\ "",
Examples
-
+request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
request(:post, "https://my.website.com", "{\"foo\": 3}", [{"Accept", "application/json"}])
do_in(envs, list)
Examples
-do_in(:dev) do
- IO.puts("This will only be printed in the dev environment")
-end
+
+do_in([:dev, :test]) do
+ IO.puts("This will only be printed in the dev and test environments")
+enddo_in(:dev) do
+ IO.puts("This will only be printed in the dev environment")
+end
-do_in([:dev, :test]) do
- IO.puts("This will only be printed in the dev and test environments")
-end
Logs
Result
struct.{"level":"<<level>>","name":"<<module>>","message":"..."],"time":<<timestamp>>}
{"message":["<<message|filepath|output>>"]}
Result
struct.
There are two kinds of output:
{"level":"<<level>>","name":"<<module>>","message":"..."],"time":<<timestamp>>}
These are usually for general logging, and debugging.
{"message":["<<message|filepath|output>>"]}
The above is the equivalent of the output of a command
diff --git a/Lightning.Collections.html b/Lightning.Collections.html index d6548d24c9..749d1b108f 100644 --- a/Lightning.Collections.html +++ b/Lightning.Collections.html @@ -308,11 +308,11 @@iex> create_collection(%{name: "New Collection", description: "Description here"})
-{:ok, %Collection{}}
+iex> create_collection(%{name: "New Collection", description: "Description here"})
+{:ok, %Collection{}}
-iex> create_collection(%{name: nil})
-{:error, %Ecto.Changeset{}}
+
iex> create_collection(%{name: nil})
+{:error, %Ecto.Changeset{}}
iex> list_collections()
-[%Collection{}, ...]
+iex> list_collections()
+[%Collection{}, ...]
-iex> list_collections(order_by: [asc: :inserted_at], preload: [:project, :user])
-[%Collection{}, ...]
+
iex> list_collections(order_by: [asc: :inserted_at], preload: [:project, :user])
+[%Collection{}, ...]
iex> update_collection(collection, %{name: "Updated Name"})
-{:ok, %Collection{}}
+iex> update_collection(collection, %{name: "Updated Name"})
+{:ok, %Collection{}}
-iex> update_collection(collection, %{name: nil})
-{:error, %Ecto.Changeset{}}
+
iex> update_collection(collection, %{name: nil})
+{:error, %Ecto.Changeset{}}
config/runtime.exs
) file.Sourcing envs
Internally this module uses
Dotenvy.source/1
to source environment variables from the.env
,.env.<config_env>
, and.env.<config_env>.override
files. It also sources the system environment variables.Calling
configure/0
without callingsource_envs/0
orDotenvy.source/2
-first will result in no environment variables being loaded.
Usage:
Lightning.Config.Bootstrap.source_envs()
-Lightning.Config.Bootstrap.configure()
+first will result in no environment variables being loaded.Usage:
Lightning.Config.Bootstrap.source_envs()
+Lightning.Config.Bootstrap.configure()
diff --git a/Lightning.Credentials.html b/Lightning.Credentials.html
index 5f16247ad6..b4091dfa36 100644
--- a/Lightning.Credentials.html
+++ b/Lightning.Credentials.html
@@ -408,8 +408,8 @@ iex> change_credential(credential)
-%Ecto.Changeset{data: %Credential{}}
+iex> change_credential(credential)
+%Ecto.Changeset{data: %Credential{}}
iex> create_credential(%{field: value})
-{:ok, %Credential{}}
+iex> create_credential(%{field: value})
+{:ok, %Credential{}}
-iex> create_credential(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_credential(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
iex> delete_credential(credential)
-{:ok, %Credential{}}
+iex> delete_credential(credential)
+{:ok, %Credential{}}
-iex> delete_credential(credential)
-{:error, %Ecto.Changeset{}}
+iex> delete_credential(credential)
+{:error, %Ecto.Changeset{}}
iex> get_credential!(123)
-%Credential{}
+iex> get_credential!(123)
+%Credential{}
-iex> get_credential!(456)
+iex> get_credential!(456)
** (Ecto.NoResultsError)
iex> has_activity_in_projects?(%Credential{id: some_id})
+iex> has_activity_in_projects?(%Credential{id: some_id})
true
-iex> has_activity_in_projects?(%Credential{id: another_id})
+iex> has_activity_in_projects?(%Credential{id: another_id})
false
@@ -661,11 +661,11 @@ invalid_projects_for_user(credential_id, us
Examples
-iex> can_credential_be_shared_to_user(credential_id, user_id)
-[]
+iex> can_credential_be_shared_to_user(credential_id, user_id)
+[]
-iex> can_credential_be_shared_to_user(credential_id, user_id)
-["52ea8758-6ce5-43d7-912f-6a1e1f11dc55"]
+iex> can_credential_be_shared_to_user(credential_id, user_id)
+["52ea8758-6ce5-43d7-912f-6a1e1f11dc55"]
@@ -705,9 +705,9 @@ list_credentials(project)
Examples
- When given a Project:
iex> list_credentials(%Project{id: 1})
-[%Credential{project_id: 1}, %Credential{project_id: 1}]
When given a User:
iex> list_credentials(%User{id: 123})
-[%Credential{user_id: 123}, %Credential{user_id: 123}]
+ When given a Project:
iex> list_credentials(%Project{id: 1})
+[%Credential{project_id: 1}, %Credential{project_id: 1}]
When given a User:
iex> list_credentials(%User{id: 123})
+[%Credential{user_id: 123}, %Credential{user_id: 123}]
@@ -818,11 +818,11 @@ schedule_credential_deletion(credential)
Examples
-iex> schedule_credential_deletion(%Credential{id: some_id})
-{:ok, %Credential{}}
+iex> schedule_credential_deletion(%Credential{id: some_id})
+{:ok, %Credential{}}
-iex> schedule_credential_deletion(%Credential{})
-{:error, %Ecto.Changeset{}}
+iex> schedule_credential_deletion(%Credential{})
+{:error, %Ecto.Changeset{}}
@@ -879,11 +879,11 @@ update_credential(credential, attrs)
Examples
-iex> update_credential(credential, %{field: new_value})
-{:ok, %Credential{}}
+iex> update_credential(credential, %{field: new_value})
+{:ok, %Credential{}}
-iex> update_credential(credential, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_credential(credential, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.Helpers.html b/Lightning.Helpers.html
index bef18e01ed..a1b39401ca 100644
--- a/Lightning.Helpers.html
+++ b/Lightning.Helpers.html
@@ -327,10 +327,10 @@ copy_error(changeset, original_key, new_key
Example
-iex> changeset = %Ecto.Changeset{errors: [name: {"has already been taken", []}]}
-iex> updated_changeset = Lightning.Helpers.copy_error(changeset, :name, :raw_name)
+iex> changeset = %Ecto.Changeset{errors: [name: {"has already been taken", []}]}
+iex> updated_changeset = Lightning.Helpers.copy_error(changeset, :name, :raw_name)
iex> updated_changeset.errors
-[name: {"has already been taken", []}, raw_name: {"has already been taken", []}]
If the original_key
doesn't exist in the errors, or if the new_key
already exists and overwrite
is set to false
, the changeset is returned unchanged.
+[name: {"has already been taken", []}, raw_name: {"has already been taken", []}]
If the original_key
doesn't exist in the errors, or if the new_key
already exists and overwrite
is set to false
, the changeset is returned unchanged.
@@ -449,10 +449,10 @@ url_safe_name(name)
Examples
-iex> url_safe_name("My Project!!")
+iex> url_safe_name("My Project!!")
"my-project"
-iex> url_safe_name(nil)
+iex> url_safe_name(nil)
""
diff --git a/Lightning.Invocation.html b/Lightning.Invocation.html
index bf59805c3a..1fb665324b 100644
--- a/Lightning.Invocation.html
+++ b/Lightning.Invocation.html
@@ -531,8 +531,8 @@ change_dataclip(dataclip, attrs \\ %{})
Examples
-iex> change_dataclip(dataclip)
-%Ecto.Changeset{data: %Dataclip{}}
+iex> change_dataclip(dataclip)
+%Ecto.Changeset{data: %Dataclip{}}
@@ -562,8 +562,8 @@ change_step(step, attrs \\ %{})
Examples
-iex> change_step(step)
-%Ecto.Changeset{data: %Step{}}
+iex> change_step(step)
+%Ecto.Changeset{data: %Step{}}
@@ -623,11 +623,11 @@ create_dataclip(attrs \\ %{})
Examples
-iex> create_dataclip(%{field: value})
-{:ok, %Dataclip{}}
+iex> create_dataclip(%{field: value})
+{:ok, %Dataclip{}}
-iex> create_dataclip(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_dataclip(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -655,11 +655,11 @@ delete_dataclip(dataclip)
Examples
-iex> delete_dataclip(dataclip)
-{:ok, %Dataclip{}}
+iex> delete_dataclip(dataclip)
+{:ok, %Dataclip{}}
-iex> delete_dataclip(dataclip)
-{:error, %Ecto.Changeset{}}
+iex> delete_dataclip(dataclip)
+{:error, %Ecto.Changeset{}}
@@ -729,14 +729,14 @@ get_dataclip(step)
Examples
-iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
-%Dataclip{}
+iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
+%Dataclip{}
-iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
+iex> get_dataclip("27b73932-16c7-4a72-86a3-85d805ccff98")
nil
-iex> get_dataclip(%Step{id: "a uuid"})
-%Dataclip{}
+iex> get_dataclip(%Step{id: "a uuid"})
+%Dataclip{}
@@ -770,10 +770,10 @@ get_dataclip!(id)
Examples
-iex> get_dataclip!(123)
-%Dataclip{}
+iex> get_dataclip!(123)
+%Dataclip{}
-iex> get_dataclip!(456)
+iex> get_dataclip!(456)
** (Ecto.NoResultsError)
@@ -971,10 +971,10 @@ get_step!(id)
Examples
-iex> get_step!(123)
-%Step{}
+iex> get_step!(123)
+%Step{}
-iex> get_step!(456)
+iex> get_step!(456)
** (Ecto.NoResultsError)
@@ -1103,8 +1103,8 @@ list_dataclips()
Examples
-iex> list_dataclips()
-[%Dataclip{}, ...]
+iex> list_dataclips()
+[%Dataclip{}, ...]
@@ -1213,8 +1213,8 @@ list_steps()
Examples
-iex> list_steps()
-[%Step{}, ...]
+iex> list_steps()
+[%Step{}, ...]
@@ -1341,7 +1341,7 @@ search_workorders(project)
Example:
-search_workorders(%Project{id: 1}, %SearchParams{status: ["completed"]})
+search_workorders(%Project{id: 1}, %SearchParams{status: ["completed"]})
@@ -1447,11 +1447,11 @@ update_dataclip(dataclip, attrs)
Examples
-iex> update_dataclip(dataclip, %{field: new_value})
-{:ok, %Dataclip{}}
+iex> update_dataclip(dataclip, %{field: new_value})
+{:ok, %Dataclip{}}
-iex> update_dataclip(dataclip, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_dataclip(dataclip, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.Jobs.html b/Lightning.Jobs.html
index 6f9c578fcb..fd8a7dfc15 100644
--- a/Lightning.Jobs.html
+++ b/Lightning.Jobs.html
@@ -308,8 +308,8 @@ change_job(job, attrs \\ %{})
Examples
-iex> change_job(job)
-%Ecto.Changeset{data: %Job{}}
+iex> change_job(job)
+%Ecto.Changeset{data: %Job{}}
@@ -339,11 +339,11 @@ create_job(attrs \\ %{})
Examples
-iex> create_job(%{field: value})
-{:ok, %Job{}}
+iex> create_job(%{field: value})
+{:ok, %Job{}}
-iex> create_job(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_job(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -407,10 +407,10 @@ get_job!(id)
Examples
-iex> get_job!(123)
-%Job{}
+iex> get_job!(123)
+%Job{}
-iex> get_job!(456)
+iex> get_job!(456)
** (Ecto.NoResultsError)
@@ -622,11 +622,11 @@ update_job(job, attrs)
Examples
-iex> update_job(job, %{field: new_value})
-{:ok, %Job{}}
+iex> update_job(job, %{field: new_value})
+{:ok, %Job{}}
-iex> update_job(job, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_job(job, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.KafkaTriggers.MessageRecovery.html b/Lightning.KafkaTriggers.MessageRecovery.html
index 2937637391..5059332988 100644
--- a/Lightning.KafkaTriggers.MessageRecovery.html
+++ b/Lightning.KafkaTriggers.MessageRecovery.html
@@ -153,7 +153,7 @@
an error during reprocessing. These files can be reprocessed if you think the
error was transient.
Usage:
alias Lightning.KafkaTriggers.MessageRecovery
case MessageRecovery.recover_messages(Lightning.Config.kafka_alternate_storage_file_path) do
:ok -> # Success code
-{:error, error_count} -> # Failure code
end
+{:error, error_count} -> # Failure code
end
diff --git a/Lightning.OauthClients.html b/Lightning.OauthClients.html
index b1a1e87468..4d1d4f8745 100644
--- a/Lightning.OauthClients.html
+++ b/Lightning.OauthClients.html
@@ -269,8 +269,8 @@ change_client(client, attrs \\ %{})
Examples
-iex> change_client(%OauthClient{}, %{name: "New Client"})
-%Ecto.Changeset{...}
+iex> change_client(%OauthClient{}, %{name: "New Client"})
+%Ecto.Changeset{...}
@@ -355,11 +355,11 @@ delete_client(client)
Examples
-iex> delete_client(client)
-{:ok, %OauthClient{}}
+iex> delete_client(client)
+{:ok, %OauthClient{}}
-iex> delete_client(client)
-{:error, %Ecto.Changeset{}}
+iex> delete_client(client)
+{:error, %Ecto.Changeset{}}
@@ -405,10 +405,10 @@ get_client!(id)
Examples
-iex> get_client!(123)
-%OauthClient{}
+iex> get_client!(123)
+%OauthClient{}
-iex> get_client!(456)
+iex> get_client!(456)
** (Ecto.NoResultsError)
@@ -449,9 +449,9 @@ list_clients(project)
Examples
- When given a Project:
iex> list_clients(%Project{id: 1})
-[%OauthClient{project_id: 1}, %OauthClient{project_id: 1}]
When given a User:
iex> list_clients(%User{id: 123})
-[%OauthClient{user_id: 123}, %OauthClient{user_id: 123}]
+ When given a Project:
iex> list_clients(%Project{id: 1})
+[%OauthClient{project_id: 1}, %OauthClient{project_id: 1}]
When given a User:
iex> list_clients(%User{id: 123})
+[%OauthClient{user_id: 123}, %OauthClient{user_id: 123}]
@@ -491,11 +491,11 @@ update_client(client, attrs)
Examples
-iex> update_client(client, %{field: new_value})
-{:ok, %OauthClient{}}
+iex> update_client(client, %{field: new_value})
+{:ok, %OauthClient{}}
-iex> update_client(client, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_client(client, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.Policies.Permissions.html b/Lightning.Policies.Permissions.html
index cf486b994d..2845ac3cc6 100644
--- a/Lightning.Policies.Permissions.html
+++ b/Lightning.Policies.Permissions.html
@@ -139,13 +139,13 @@
This module defines a unique interface managing authorizations in Lightning.
Users in Lightning have instance-wide and project-wide roles which determine their level of access to resources in the application. Fo rmore details see the documentation.
These authorizations policies are all implemented under the lib/lightning/policies
folder. In that folder you can find 3 files:
- The
users.ex
file has all the policies for the instances wide access levels - The
project_users.ex
file has all the policies for the project wide access levels - The
permissions.ex
file defines the Lightning.Policies.Permissions.can/4
interface. Which is a wrapper around the Bodyguard.permit/4
function.
-We use that interface to be able to harmonize the use of policies accross the entire app.
All the policies are tested in the test/lightning/policies
folder. And the test are written in a way that allows the reader to quickly who can do what in the app.
We have two variants of the Lightning.Policies.Permissions.can/4
interface:
Lightning.Policies.Permissions.can(policy, action, actor, resource)
returns :ok
if the actor can perform the action on the resource and {:error, :unauthorized}
otherwise.Lightning.Policies.Permissions.can?(policy, action, actor, resource)
returns true
if the actor can perform the action on the resource and false
otherwise.
Here is an example of how we the Lightning.Policies.Permissions.can/4
interface to check if the a user can edit a job or not
can_edit_workflow = Lightning.Policies.ProjectUsers |> Lightning.Policies.Permissions.can?(:edit_workflow, socket.assigns.current_user, socket.assigns.project)
+We use that interface to be able to harmonize the use of policies accross the entire app.All the policies are tested in the test/lightning/policies
folder. And the test are written in a way that allows the reader to quickly who can do what in the app.
We have two variants of the Lightning.Policies.Permissions.can/4
interface:
Lightning.Policies.Permissions.can(policy, action, actor, resource)
returns :ok
if the actor can perform the action on the resource and {:error, :unauthorized}
otherwise.Lightning.Policies.Permissions.can?(policy, action, actor, resource)
returns true
if the actor can perform the action on the resource and false
otherwise.
Here is an example of how we the Lightning.Policies.Permissions.can/4
interface to check if the a user can edit a job or not
can_edit_workflow = Lightning.Policies.ProjectUsers |> Lightning.Policies.Permissions.can?(:edit_workflow, socket.assigns.current_user, socket.assigns.project)
-if can_edit_workflow do
+if can_edit_workflow do
# allow user to edit the workflow
-else
+else
# quick user out
-end
+end
@@ -222,11 +222,11 @@ can(policy, action, user, params \\ [])
Examples
-iex> can(Lightning.Policies.Users, :create_workflow, user, project)
+iex> can(Lightning.Policies.Users, :create_workflow, user, project)
:ok
-iex> can(Lightning.Policies.Users, :create_project, user, %{})
-{:error, :unauthorized}
+iex> can(Lightning.Policies.Users, :create_project, user, %{})
+{:error, :unauthorized}
@@ -256,10 +256,10 @@ can?(policy, action, user, params \\ [])
Examples
-iex> can(Lightning.Policies.Users, :create_workflow, user, project)
+iex> can(Lightning.Policies.Users, :create_workflow, user, project)
true
-iex> can(Lightning.Policies.Users, :create_project, user, %{})
+iex> can(Lightning.Policies.Users, :create_project, user, %{})
false
diff --git a/Lightning.Projects.html b/Lightning.Projects.html
index d929031cf8..35dc44054a 100644
--- a/Lightning.Projects.html
+++ b/Lightning.Projects.html
@@ -692,8 +692,8 @@ change_project(project, attrs \\ %{})
Examples
-iex> change_project(project)
-%Ecto.Changeset{data: %Project{}}
+iex> change_project(project)
+%Ecto.Changeset{data: %Project{}}
@@ -725,11 +725,11 @@ create_project(attrs \\ %{}, schedule_email
Examples
-iex> create_project(%{field: value})
-{:ok, %Project{}}
+iex> create_project(%{field: value})
+{:ok, %Project{}}
-iex> create_project(%{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> create_project(%{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -758,11 +758,11 @@ delete_project(project)
Examples
-iex> delete_project(project)
-{:ok, %Project{}}
+iex> delete_project(project)
+{:ok, %Project{}}
-iex> delete_project(project)
-{:error, %Ecto.Changeset{}}
+iex> delete_project(project)
+{:error, %Ecto.Changeset{}}
@@ -917,8 +917,8 @@ export_project(atom, project_id, snapshot_i
Examples
-iex> export_project(:yaml, project_id)
-{:ok, string}
+iex> export_project(:yaml, project_id)
+{:ok, string}
@@ -990,10 +990,10 @@ get_project!(id)
Examples
-iex> get_project!(123)
-%Project{}
+iex> get_project!(123)
+%Project{}
-iex> get_project!(456)
+iex> get_project!(456)
** (Ecto.NoResultsError)
@@ -1088,10 +1088,10 @@ get_project_user!(id)
Examples
-iex> get_project_user!(123)
-%ProjectUser{}
+iex> get_project_user!(123)
+%ProjectUser{}
-iex> get_project_user!(456)
+iex> get_project_user!(456)
** (Ecto.NoResultsError)
@@ -1121,16 +1121,16 @@ get_project_user_role(user, project)
Examples
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:admin
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:viewer
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:editor
-iex> get_project_user_role(user, project)
+iex> get_project_user_role(user, project)
:owner
@@ -1181,10 +1181,10 @@ get_project_with_users!(id)
Examples
-iex> get_project!(123)
-%Project{}
+iex> get_project!(123)
+%Project{}
-iex> get_project!(456)
+iex> get_project!(456)
** (Ecto.NoResultsError)
@@ -1386,8 +1386,8 @@ list_projects()
Examples
-iex> list_projects()
-[%Project{}, ...]
+iex> list_projects()
+[%Project{}, ...]
@@ -1869,11 +1869,11 @@ update_project(project, attrs, user \\ nil)
Examples
-iex> update_project(project, %{field: new_value})
-{:ok, %Project{}}
+iex> update_project(project, %{field: new_value})
+{:ok, %Project{}}
-iex> update_project(project, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_project(project, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -1901,11 +1901,11 @@ update_project_user(project_user, attrs)
Examples
-iex> update_project_user(project_user, %{field: new_value})
-{:ok, %ProjectUser{}}
+iex> update_project_user(project_user, %{field: new_value})
+{:ok, %ProjectUser{}}
-iex> update_project_user(projectUser, %{field: bad_value})
-{:error, %Ecto.Changeset{}}
+iex> update_project_user(projectUser, %{field: bad_value})
+{:error, %Ecto.Changeset{}}
@@ -1964,8 +1964,8 @@ validate_for_deletion(project, attrs)
Examples
-iex> validate_for_deletion(project)
-%Ecto.Changeset{data: %Project{}}
+iex> validate_for_deletion(project)
+%Ecto.Changeset{data: %Project{}}
diff --git a/Lightning.PromEx.html b/Lightning.PromEx.html
index a5afacbce3..7ddc704640 100644
--- a/Lightning.PromEx.html
+++ b/Lightning.PromEx.html
@@ -143,24 +143,24 @@
more details regarding configuring PromEx:config :lightning, Lightning.PromEx,
disabled: false,
manual_metrics_start_delay: :no_delay,
- drop_metrics_groups: [],
+ drop_metrics_groups: [],
grafana: :disabled,
metrics_server: :disabled
Add this module to your application supervision tree. It should be one of the first
things that is started so that no Telemetry events are missed. For example, if PromEx
is started after your Repo module, you will miss Ecto's init events and the dashboards
-will be missing some data points:
def start(_type, _args) do
- children = [
+will be missing some data points:def start(_type, _args) do
+ children = [
Lightning.PromEx,
...
- ]
+ ]
...
-end
Update your endpoint.ex
file to expose your metrics (or configure a standalone
+
end
Update your endpoint.ex
file to expose your metrics (or configure a standalone
server using the :metrics_server
config options). Be sure to put this plug before
your Plug.Telemetry
entry so that you can avoid having calls to your /metrics
endpoint create their own metrics and logs which can pollute your logs/metrics given
-that Prometheus will scrape at a regular interval and that can get noisy:
defmodule LightningWeb.Endpoint do
+that Prometheus will scrape at a regular interval and that can get noisy:defmodule LightningWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :lightning
...
@@ -168,7 +168,7 @@
plug PromEx.Plug, prom_ex_module: Lightning.PromEx
...
-end
Update the list of plugins in the plugins/0
function return list to reflect your
+
end
Update the list of plugins in the plugins/0
function return list to reflect your
application's dependencies. Also update the list of dashboards that are to be uploaded
to Grafana in the dashboards/0
function.
diff --git a/Lightning.Repo.html b/Lightning.Repo.html
index 87397a341d..5559dc2604 100644
--- a/Lightning.Repo.html
+++ b/Lightning.Repo.html
@@ -1740,13 +1740,13 @@ transact(fun, opts \\ [])
A small wrapper around Repo.transaction/2
.
Commits the transaction if the lambda returns :ok
or {:ok, result}
,
rolling it back if the lambda returns :error
or {:error, reason}
. In both
-cases, the function returns the result of the lambda.
Example:
Repo.transact(fn ->
- with {:ok, user} <- Accounts.create_user(params),
- {:ok, _log} <- Logs.log_action(:user_registered, user),
- {:ok, _job} <- Mailer.enqueue_email_confirmation(user) do
- {:ok, user}
- end
-end)
From blog post found here
+cases, the function returns the result of the lambda.Example:
Repo.transact(fn ->
+ with {:ok, user} <- Accounts.create_user(params),
+ {:ok, _log} <- Logs.log_action(:user_registered, user),
+ {:ok, _job} <- Mailer.enqueue_email_confirmation(user) do
+ {:ok, user}
+ end
+end)
From blog post found here
diff --git a/Lightning.Runs.Query.html b/Lightning.Runs.Query.html
index 611f00aa72..36dbdda826 100644
--- a/Lightning.Runs.Query.html
+++ b/Lightning.Runs.Query.html
@@ -243,7 +243,7 @@ eligible_for_claim()
This query does not currently take into account the priority of the run.
To allow for prioritization, the query should be updated to order by
-priority.
eligible_for_claim() |> prepend_order_by([:priority])
+priority.eligible_for_claim() |> prepend_order_by([:priority])
diff --git a/Lightning.Runs.html b/Lightning.Runs.html
index 8abccd5c76..ed0d5ba816 100644
--- a/Lightning.Runs.html
+++ b/Lightning.Runs.html
@@ -479,7 +479,7 @@ get(id, opts \\ [])
-Get a run by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.Runs.get(id, include: [:workflow])
+Get a run by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.Runs.get(id, include: [:workflow])
diff --git a/Lightning.Runtime.LogAgent.html b/Lightning.Runtime.LogAgent.html
index a3e19d9abb..4d16da13f1 100644
--- a/Lightning.Runtime.LogAgent.html
+++ b/Lightning.Runtime.LogAgent.html
@@ -139,9 +139,9 @@
Agent facility to consume STDOUT/STDERR byte by byte.
Since it works on a byte by byte basis, you will need to perform line-splitting
-yourself.
Usage:
{:ok, log} = LogAgent.start_link()
-"foo" = LogAgent.process_chunk(log, {:stdout, "foo"})
-"foobar" = LogAgent.process_chunk(log, {:stdout, "bar"})
+yourself.Usage:
{:ok, log} = LogAgent.start_link()
+"foo" = LogAgent.process_chunk(log, {:stdout, "foo"})
+"foobar" = LogAgent.process_chunk(log, {:stdout, "bar"})
diff --git a/Lightning.Runtime.RuntimeManager.html b/Lightning.Runtime.RuntimeManager.html
index f785cafc98..6b347edbaa 100644
--- a/Lightning.Runtime.RuntimeManager.html
+++ b/Lightning.Runtime.RuntimeManager.html
@@ -147,8 +147,8 @@
Sample:
config :lightining, Elixir.Lightning.Runtime.RuntimeManager,
version: "0.1.0",
start: true,
args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
-cd: Path.expand("../assets", __DIR__),
-env: %{}
Options:
:version
- the expected runtime version
:start
- flag to start the runtime manager. If false
the GenServer
+
cd: Path.expand("../assets", __DIR__),
+env: %{}
Options:
:version
- the expected runtime version
:start
- flag to start the runtime manager. If false
the GenServer
won't be started
:path
- the path to find the runtime executable at. By
default, it is automatically downloaded and placed inside
the _build
directory of your current app
Overriding the :path
is not recommended, as we will automatically
diff --git a/Lightning.Scrubber.html b/Lightning.Scrubber.html
index d9bd011884..81009a6d81 100644
--- a/Lightning.Scrubber.html
+++ b/Lightning.Scrubber.html
@@ -138,11 +138,11 @@
-Process used to scrub strings of sensitive information.
Can be started via start_link/1
.
{:ok, scrubber} =
- Lightning.Scrubber.start_link(
+Process used to scrub strings of sensitive information.
Can be started via start_link/1
.
{:ok, scrubber} =
+ Lightning.Scrubber.start_link(
samples:
- Lightning.Credentials.sensitive_values_for(credential)
- )
Takes an optional :name
key, in case you need to name the process.
+ Lightning.Credentials.sensitive_values_for(credential)
+ )
Takes an optional :name
key, in case you need to name the process.
diff --git a/Lightning.Storage.GCS.html b/Lightning.Storage.GCS.html
index b310676f8e..ae9db8da02 100644
--- a/Lightning.Storage.GCS.html
+++ b/Lightning.Storage.GCS.html
@@ -151,10 +151,10 @@
Example Usage
# Store a file in GCS
-Lightning.Storage.GCS.store("/path/to/source", "destination/path")
+Lightning.Storage.GCS.store("/path/to/source", "destination/path")
# Get a signed URL for the stored file
-{:ok, url} = Lightning.Storage.GCS.get_url("destination/path")
+
{:ok, url} = Lightning.Storage.GCS.get_url("destination/path")
diff --git a/Lightning.Storage.Local.html b/Lightning.Storage.Local.html
index 01cbfbed49..efa80438c4 100644
--- a/Lightning.Storage.Local.html
+++ b/Lightning.Storage.Local.html
@@ -157,11 +157,11 @@ # Store a file
-{:ok, filename} =
- Lightning.Storage.Local.store("/path/to/source", "destination/path")
+{:ok, filename} =
+ Lightning.Storage.Local.store("/path/to/source", "destination/path")
# Get the URL for the stored file
-{:ok, url} = Lightning.Storage.Local.get_url("destination/path")
+{:ok, url} = Lightning.Storage.Local.get_url("destination/path")
diff --git a/Lightning.Storage.ProjectFileDefinition.html b/Lightning.Storage.ProjectFileDefinition.html
index 8b4e390b7d..bdbcf4664b 100644
--- a/Lightning.Storage.ProjectFileDefinition.html
+++ b/Lightning.Storage.ProjectFileDefinition.html
@@ -139,13 +139,13 @@ This module provides functionality for managing the storage and retrieval of project files.
It handles operations related to storing project files, generating URLs for accessing these files, and constructing storage paths for exported files. It serves as an abstraction layer over the underlying storage mechanism provided by the Lightning.Storage
module.
## Functions
store/2
: Stores a file from a given source path into the storage system based on the file's path.get_url/1
: Retrieves the URL for accessing a stored file.storage_path_for_exports/2
: Constructs a storage path for exported files, defaulting to a .zip
extension.## Example Usage
# Store a file
- Lightning.Storage.ProjectFileDefinition.store("/path/to/source", project_file)
+ Lightning.Storage.ProjectFileDefinition.store("/path/to/source", project_file)
# Get a URL for the stored file
- url = Lightning.Storage.ProjectFileDefinition.get_url(project_file)
+ url = Lightning.Storage.ProjectFileDefinition.get_url(project_file)
# Get the storage path for an exported file
- path = Lightning.Storage.ProjectFileDefinition.storage_path_for_exports(project_file)
+ path = Lightning.Storage.ProjectFileDefinition.storage_path_for_exports(project_file)
A TaskWorker with concurrency limits.
A simple concurrency limiter that wraps Task.Supervisor
, which already does
have the ability to specify max_children
; it throws an error when
that limit is exceeded.
To use it, start it like any other process; ideally in your supervision tree.
...,
- {Lightning.TaskWorker, name: :cli_task_worker, max_tasks: 4}
Options
:max_tasks
Defaults to the number of system schedulers available to the vm.Options
:max_tasks
Defaults to the number of system schedulers available to the vm.Validate that only one of the fields is set at a time.
Example:
changeset
-|> validate_exclusive(
- [:source_job_id, :source_trigger_id],
+|> validate_exclusive(
+ [:source_job_id, :source_trigger_id],
"source_job_id and source_trigger_id are mutually exclusive"
-)
+)
Perform a DELETE request.
See request/1
or request/2
for options definition.
delete("/users")
-delete("/users", query: [scope: "admin"])
-delete(client, "/users")
-delete(client, "/users", query: [scope: "admin"])
-delete(client, "/users", body: %{name: "Jon"})
+Perform a DELETE request.
See request/1
or request/2
for options definition.
delete("/users")
+delete("/users", query: [scope: "admin"])
+delete(client, "/users")
+delete(client, "/users", query: [scope: "admin"])
+delete(client, "/users", body: %{name: "Jon"})
Perform a DELETE request.
See request!/1
or request!/2
for options definition.
delete!("/users")
-delete!("/users", query: [scope: "admin"])
-delete!(client, "/users")
-delete!(client, "/users", query: [scope: "admin"])
-delete!(client, "/users", body: %{name: "Jon"})
+Perform a DELETE request.
See request!/1
or request!/2
for options definition.
delete!("/users")
+delete!("/users", query: [scope: "admin"])
+delete!(client, "/users")
+delete!(client, "/users", query: [scope: "admin"])
+delete!(client, "/users", body: %{name: "Jon"})
Perform a GET request.
See request/1
or request/2
for options definition.
get("/users")
-get("/users", query: [scope: "admin"])
-get(client, "/users")
-get(client, "/users", query: [scope: "admin"])
-get(client, "/users", body: %{name: "Jon"})
+Perform a GET request.
See request/1
or request/2
for options definition.
get("/users")
+get("/users", query: [scope: "admin"])
+get(client, "/users")
+get(client, "/users", query: [scope: "admin"])
+get(client, "/users", body: %{name: "Jon"})
Perform a GET request.
See request!/1
or request!/2
for options definition.
get!("/users")
-get!("/users", query: [scope: "admin"])
-get!(client, "/users")
-get!(client, "/users", query: [scope: "admin"])
-get!(client, "/users", body: %{name: "Jon"})
+Perform a GET request.
See request!/1
or request!/2
for options definition.
get!("/users")
+get!("/users", query: [scope: "admin"])
+get!(client, "/users")
+get!(client, "/users", query: [scope: "admin"])
+get!(client, "/users", body: %{name: "Jon"})
Perform a HEAD request.
See request/1
or request/2
for options definition.
head("/users")
-head("/users", query: [scope: "admin"])
-head(client, "/users")
-head(client, "/users", query: [scope: "admin"])
-head(client, "/users", body: %{name: "Jon"})
+Perform a HEAD request.
See request/1
or request/2
for options definition.
head("/users")
+head("/users", query: [scope: "admin"])
+head(client, "/users")
+head(client, "/users", query: [scope: "admin"])
+head(client, "/users", body: %{name: "Jon"})
Perform a HEAD request.
See request!/1
or request!/2
for options definition.
head!("/users")
-head!("/users", query: [scope: "admin"])
-head!(client, "/users")
-head!(client, "/users", query: [scope: "admin"])
-head!(client, "/users", body: %{name: "Jon"})
+Perform a HEAD request.
See request!/1
or request!/2
for options definition.
head!("/users")
+head!("/users", query: [scope: "admin"])
+head!(client, "/users")
+head!(client, "/users", query: [scope: "admin"])
+head!(client, "/users", body: %{name: "Jon"})
Perform a OPTIONS request.
See request/1
or request/2
for options definition.
options("/users")
-options("/users", query: [scope: "admin"])
-options(client, "/users")
-options(client, "/users", query: [scope: "admin"])
-options(client, "/users", body: %{name: "Jon"})
+Perform a OPTIONS request.
See request/1
or request/2
for options definition.
options("/users")
+options("/users", query: [scope: "admin"])
+options(client, "/users")
+options(client, "/users", query: [scope: "admin"])
+options(client, "/users", body: %{name: "Jon"})
Perform a OPTIONS request.
See request!/1
or request!/2
for options definition.
options!("/users")
-options!("/users", query: [scope: "admin"])
-options!(client, "/users")
-options!(client, "/users", query: [scope: "admin"])
-options!(client, "/users", body: %{name: "Jon"})
+Perform a OPTIONS request.
See request!/1
or request!/2
for options definition.
options!("/users")
+options!("/users", query: [scope: "admin"])
+options!(client, "/users")
+options!(client, "/users", query: [scope: "admin"])
+options!(client, "/users", body: %{name: "Jon"})
Perform a PATCH request.
See request/1
or request/2
for options definition.
patch("/users", %{name: "Jon"})
-patch("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch(client, "/users", %{name: "Jon"})
-patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PATCH request.
See request/1
or request/2
for options definition.
patch("/users", %{name: "Jon"})
+patch("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch(client, "/users", %{name: "Jon"})
+patch(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a PATCH request.
See request!/1
or request!/2
for options definition.
patch!("/users", %{name: "Jon"})
-patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
-patch!(client, "/users", %{name: "Jon"})
-patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PATCH request.
See request!/1
or request!/2
for options definition.
patch!("/users", %{name: "Jon"})
+patch!("/users", %{name: "Jon"}, query: [scope: "admin"])
+patch!(client, "/users", %{name: "Jon"})
+patch!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a POST request.
See request/1
or request/2
for options definition.
post("/users", %{name: "Jon"})
-post("/users", %{name: "Jon"}, query: [scope: "admin"])
-post(client, "/users", %{name: "Jon"})
-post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a POST request.
See request/1
or request/2
for options definition.
post("/users", %{name: "Jon"})
+post("/users", %{name: "Jon"}, query: [scope: "admin"])
+post(client, "/users", %{name: "Jon"})
+post(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a POST request.
See request!/1
or request!/2
for options definition.
post!("/users", %{name: "Jon"})
-post!("/users", %{name: "Jon"}, query: [scope: "admin"])
-post!(client, "/users", %{name: "Jon"})
-post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a POST request.
See request!/1
or request!/2
for options definition.
post!("/users", %{name: "Jon"})
+post!("/users", %{name: "Jon"}, query: [scope: "admin"])
+post!(client, "/users", %{name: "Jon"})
+post!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a PUT request.
See request/1
or request/2
for options definition.
put("/users", %{name: "Jon"})
-put("/users", %{name: "Jon"}, query: [scope: "admin"])
-put(client, "/users", %{name: "Jon"})
-put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PUT request.
See request/1
or request/2
for options definition.
put("/users", %{name: "Jon"})
+put("/users", %{name: "Jon"}, query: [scope: "admin"])
+put(client, "/users", %{name: "Jon"})
+put(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
Perform a PUT request.
See request!/1
or request!/2
for options definition.
put!("/users", %{name: "Jon"})
-put!("/users", %{name: "Jon"}, query: [scope: "admin"])
-put!(client, "/users", %{name: "Jon"})
-put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
+Perform a PUT request.
See request!/1
or request!/2
for options definition.
put!("/users", %{name: "Jon"})
+put!("/users", %{name: "Jon"}, query: [scope: "admin"])
+put!(client, "/users", %{name: "Jon"})
+put!(client, "/users", %{name: "Jon"}, query: [scope: "admin"])
ExampleApi.request(method: :get, url: "/users/path")
+ExampleApi.request(method: :get, url: "/users/path")
# use shortcut methods
-ExampleApi.get("/users/1")
-ExampleApi.post(client, "/users", %{name: "Jon"})
+ExampleApi.get("/users/1")
+ExampleApi.post(client, "/users", %{name: "Jon"})
Perform a TRACE request.
See request/1
or request/2
for options definition.
trace("/users")
-trace("/users", query: [scope: "admin"])
-trace(client, "/users")
-trace(client, "/users", query: [scope: "admin"])
-trace(client, "/users", body: %{name: "Jon"})
+Perform a TRACE request.
See request/1
or request/2
for options definition.
trace("/users")
+trace("/users", query: [scope: "admin"])
+trace(client, "/users")
+trace(client, "/users", query: [scope: "admin"])
+trace(client, "/users", body: %{name: "Jon"})
Perform a TRACE request.
See request!/1
or request!/2
for options definition.
trace!("/users")
-trace!("/users", query: [scope: "admin"])
-trace!(client, "/users")
-trace!(client, "/users", query: [scope: "admin"])
-trace!(client, "/users", body: %{name: "Jon"})
+Perform a TRACE request.
See request!/1
or request!/2
for options definition.
trace!("/users")
+trace!("/users", query: [scope: "admin"])
+trace!(client, "/users")
+trace!(client, "/users", query: [scope: "admin"])
+trace!(client, "/users", body: %{name: "Jon"})
Creating a WebhookAuthMethod
without an associated trigger:
iex> create_auth_method(%{valid_attributes}, actor: %User{})
-{:ok, %WebhookAuthMethod{}}
+Creating a WebhookAuthMethod
without an associated trigger:
iex> create_auth_method(%{valid_attributes}, actor: %User{})
+{:ok, %WebhookAuthMethod{}}
-iex> create_auth_method(%{invalid_attributes}, actor: %User{})
-{:error, %Ecto.Changeset{}}
Creating a WebhookAuthMethod
with an associated trigger:
iex> create_auth_method(%Trigger{}, %{valid_attributes}, actor: %User{})
-{:ok, %WebhookAuthMethod{}}
+iex> create_auth_method(%{invalid_attributes}, actor: %User{})
+{:error, %Ecto.Changeset{}}
Creating a WebhookAuthMethod
with an associated trigger:
iex> create_auth_method(%Trigger{}, %{valid_attributes}, actor: %User{})
+{:ok, %WebhookAuthMethod{}}
-iex> create_auth_method(%Trigger{}, %{invalid_attributes}, actor: %User{})
-{:error, %Ecto.Changeset{}}
+
iex> create_auth_method(%Trigger{}, %{invalid_attributes}, actor: %User{})
+{:error, %Ecto.Changeset{}}
Creating a changeset for an API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :api}, %{})
-%WebhookAuthMethod{api_key: some_new_api_key}
Creating a changeset for a non-API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :other}, %{})
-%WebhookAuthMethod{}
Creating a changeset for an API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :api}, %{})
+%WebhookAuthMethod{api_key: some_new_api_key}
Creating a changeset for a non-API type auth method:
iex> Lightning.Workflows.create_changeset(%WebhookAuthMethod{auth_type: :other}, %{})
+%WebhookAuthMethod{}
Successful deletion:
iex> delete_auth_method(%WebhookAuthMethod{id: "some_id"})
-{:ok, %WebhookAuthMethod{}}
Deletion fails due to the item not existing or other conflict:
iex> delete_auth_method(%WebhookAuthMethod{id: "non_existing_id"})
-{:error, reason}
Successful deletion:
iex> delete_auth_method(%WebhookAuthMethod{id: "some_id"})
+{:ok, %WebhookAuthMethod{}}
Deletion fails due to the item not existing or other conflict:
iex> delete_auth_method(%WebhookAuthMethod{id: "non_existing_id"})
+{:error, reason}
When a matching WebhookAuthMethod
is found:
iex> Lightning.Workflows.find_by_api_key("existing_api_key", %Project{id: "existing_project_id"})
-%WebhookAuthMethod{}
When there is no matching WebhookAuthMethod
:
iex> Lightning.Workflows.find_by_api_key("non_existing_api_key", %Project{id: "existing_project_id"})
+When a matching WebhookAuthMethod
is found:
iex> Lightning.Workflows.find_by_api_key("existing_api_key", %Project{id: "existing_project_id"})
+%WebhookAuthMethod{}
When there is no matching WebhookAuthMethod
:
iex> Lightning.Workflows.find_by_api_key("non_existing_api_key", %Project{id: "existing_project_id"})
nil
When a WebhookAuthMethod
with the given ID exists:
iex> Lightning.Workflows.find_by_id!("existing_id")
-%WebhookAuthMethod{}
When there is no WebhookAuthMethod
with the given ID:
iex> Lightning.Workflows.find_by_id!("non_existing_id")
+When a WebhookAuthMethod
with the given ID exists:
iex> Lightning.Workflows.find_by_id!("existing_id")
+%WebhookAuthMethod{}
When there is no WebhookAuthMethod
with the given ID:
iex> Lightning.Workflows.find_by_id!("non_existing_id")
** (Ecto.NoResultsError)
@@ -654,8 +654,8 @@ find_by_username_and_password(username, pas
Examples
-When a matching WebhookAuthMethod
is found and the password is valid:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "valid_password", %Project{id: "existing_project_id"})
-%WebhookAuthMethod{}
When the username is found but the password is invalid or no matching record is found:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "invalid_password", %Project{id: "existing_project_id"})
+When a matching WebhookAuthMethod
is found and the password is valid:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "valid_password", %Project{id: "existing_project_id"})
+%WebhookAuthMethod{}
When the username is found but the password is invalid or no matching record is found:
iex> Lightning.Workflows.find_by_username_and_password("existing_username", "invalid_password", %Project{id: "existing_project_id"})
nil
@@ -704,9 +704,9 @@ list_for_project(project)
Examples
-When the project exists and has associated auth methods:
iex> list_for_project(%Project{id: "existing_project_id"})
-[%WebhookAuthMethod{}, ...]
When the project does not exist or has no associated auth methods:
iex> list_for_project(%Project{id: "non_existing_project_id"})
-[]
+When the project exists and has associated auth methods:
iex> list_for_project(%Project{id: "existing_project_id"})
+[%WebhookAuthMethod{}, ...]
When the project does not exist or has no associated auth methods:
iex> list_for_project(%Project{id: "non_existing_project_id"})
+[]
@@ -754,9 +754,9 @@ list_for_trigger(trigger)
Examples
-When the Trigger
has associated WebhookAuthMethod
s not scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "existing_trigger_id"})
-[%WebhookAuthMethod{}, ...]
When the Trigger
has no associated WebhookAuthMethod
s or they are all scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "trigger_without_methods"})
-[]
+When the Trigger
has associated WebhookAuthMethod
s not scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "existing_trigger_id"})
+[%WebhookAuthMethod{}, ...]
When the Trigger
has no associated WebhookAuthMethod
s or they are all scheduled for deletion:
iex> Lightning.Workflows.list_for_trigger(%Trigger{id: "trigger_without_methods"})
+[]
@@ -809,10 +809,10 @@ perform(job)
Example
-%Oban.Job{
-args: %{"type" => "purge_deleted"}
-}
-|> MyModule.perform()
+%Oban.Job{
+args: %{"type" => "purge_deleted"}
+}
+|> MyModule.perform()
# => {:ok, %{disassociated_count: 2, deleted_count: 2}}
@@ -866,9 +866,9 @@ schedule_for_deletion(webhook_auth_method,
Examples
-When a webhook auth method is successfully scheduled for deletion:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{id: some_id})
-{:ok, %WebhookAuthMethod{scheduled_deletion: deletion_date}}
When scheduling for deletion fails due to validation errors:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{})
-{:error, %Ecto.Changeset{}}
+When a webhook auth method is successfully scheduled for deletion:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{id: some_id})
+{:ok, %WebhookAuthMethod{scheduled_deletion: deletion_date}}
When scheduling for deletion fails due to validation errors:
iex> Lightning.Workflows.schedule_for_deletion(%WebhookAuthMethod{})
+{:error, %Ecto.Changeset{}}
@@ -918,9 +918,9 @@ update_auth_method(webhook_auth_method, att
Examples
-Successful update:
iex> update_auth_method(webhook_auth_method, %{field: new_value}, actor: %User{})
-{:ok, %WebhookAuthMethod{}}
Update fails due to invalid data:
iex> update_auth_method(webhook_auth_method, %{field: bad_value}, actor: %User{})
-{:error, %Ecto.Changeset{}}
+Successful update:
iex> update_auth_method(webhook_auth_method, %{field: new_value}, actor: %User{})
+{:ok, %WebhookAuthMethod{}}
Update fails due to invalid data:
iex> update_auth_method(webhook_auth_method, %{field: bad_value}, actor: %User{})
+{:error, %Ecto.Changeset{}}
@@ -976,9 +976,9 @@ update_trigger_auth_methods(trigger, auth_m
Examples
-Successful association update:
iex> update_trigger_auth_methods(trigger, [webhook_auth_method], actor: %User{})
-{:ok, %Trigger{}}
Update fails due to an invalid changeset:
iex> update_trigger_auth_methods(trigger, [invalid_webhook_auth_method], actor: %User{})
-{:error, %Ecto.Changeset{}}
+Successful association update:
iex> update_trigger_auth_methods(trigger, [webhook_auth_method], actor: %User{})
+{:ok, %Trigger{}}
Update fails due to an invalid changeset:
iex> update_trigger_auth_methods(trigger, [invalid_webhook_auth_method], actor: %User{})
+{:error, %Ecto.Changeset{}}
diff --git a/Lightning.WorkOrders.ExportWorker.html b/Lightning.WorkOrders.ExportWorker.html
index e4cd54a38d..a2efe06a99 100644
--- a/Lightning.WorkOrders.ExportWorker.html
+++ b/Lightning.WorkOrders.ExportWorker.html
@@ -139,7 +139,7 @@
This module handles the export of work orders for a given project. The export process is performed asynchronously using the Oban background job system.
## Responsibilities
- Enqueueing Export Jobs: The
enqueue_export/2
function creates and enqueues an Oban job for exporting work orders based on the given project and search parameters. - Processing Exports: The
perform/1
function is the main entry point for executing the export job. It retrieves the project, processes work orders, and handles the export process. - Export Logic: The export logic involves querying work orders, extracting relevant entities, processing logs and dataclips asynchronously, and writing the final export data to files.
- Error Handling: The module includes comprehensive error handling and logging to ensure that issues during the export process are recorded and can be diagnosed.
- Zip File Creation: After processing, the exported files are compressed into a zip file for easy download or further use.
## Usage
- To enqueue an export job, call
enqueue_export/2
with the project and search parameters. - The export process is triggered by Oban and runs in the
history_exports
queue, limited to a single attempt per job.
## Example
# Enqueue an export job
- Lightning.WorkOrders.ExportWorker.enqueue_export(project, search_params)
+ Lightning.WorkOrders.ExportWorker.enqueue_export(project, search_params)
# The job will run in the background and log the status of the export process.
This module is designed to handle potentially large datasets efficiently by using streaming, async processing, and error recovery mechanisms.
diff --git a/Lightning.WorkOrders.html b/Lightning.WorkOrders.html
index 92d910b19b..befccb3c62 100644
--- a/Lightning.WorkOrders.html
+++ b/Lightning.WorkOrders.html
@@ -453,7 +453,7 @@ create_for(target, multi \\ Multi.new(), op
-
Create a new Work Order.
For a webhook
create_for(trigger, workflow: workflow, dataclip: dataclip)
For a user
create_for(job, workflow: workflow, dataclip: dataclip, user: user)
+Create a new Work Order.
For a webhook
create_for(trigger, workflow: workflow, dataclip: dataclip)
For a user
create_for(job, workflow: workflow, dataclip: dataclip, user: user)
@@ -505,7 +505,7 @@ get(id, opts \\ [])
-Get a Work Order by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.WorkOrders.get(id, include: [:runs])
+Get a Work Order by id.
Optionally preload associations by passing a list of atoms to :include
.
Lightning.WorkOrders.get(id, include: [:runs])
diff --git a/Lightning.Workflows.Job.html b/Lightning.Workflows.Job.html
index 12eeaa46d9..f9482e118f 100644
--- a/Lightning.Workflows.Job.html
+++ b/Lightning.Workflows.Job.html
@@ -358,17 +358,17 @@ put_workflow(changeset, workflow)
Attaches a workflow to a job, this is useful when you have an unpersisted
Workflow changeset - and want it to be created at the same time as a Job.
Example:
workflow =
- Ecto.Changeset.cast(
- %Lightning.Workflows.Workflow{},
- %{ "project_id" => attrs[:project_id], "id" => Ecto.UUID.generate() },
- [:project_id, :id]
- )
+ Ecto.Changeset.cast(
+ %Lightning.Workflows.Workflow{},
+ %{ "project_id" => attrs[:project_id], "id" => Ecto.UUID.generate() },
+ [:project_id, :id]
+ )
job =
- %Job{}
- |> Ecto.Changeset.change()
- |> Job.put_workflow(workflow)
- |> Job.changeset(attrs)
+
%Job{}
+ |> Ecto.Changeset.change()
+ |> Job.put_workflow(workflow)
+ |> Job.changeset(attrs)
diff --git a/Lightning.Workflows.Presence.html b/Lightning.Workflows.Presence.html
index 48bc2ff5fe..0b2adf9dce 100644
--- a/Lightning.Workflows.Presence.html
+++ b/Lightning.Workflows.Presence.html
@@ -354,27 +354,27 @@ build_presences_summary(presences, params)<
Examples
-iex> presences = [
-...> %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
-...> %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
-...> %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
-...> ]
-iex> params = %{
-...> current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
-...> current_user: %{id: 1},
-...> view_only_users_ids: [2]
-...> }
-iex> build_presences_summary(presences, params)
-%{
- presences: [
- %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
- %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
- %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
- ],
- prior_user_presence: %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1},
- current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+iex> presences = [
+...> %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+...> %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
+...> %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
+...> ]
+iex> params = %{
+...> current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+...> current_user: %{id: 1},
+...> view_only_users_ids: [2]
+...> }
+iex> build_presences_summary(presences, params)
+%{
+ presences: [
+ %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
+ %{user: %{id: 2}, joined_at: ~N[2024-07-03 12:05:00], active_sessions: 1},
+ %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1}
+ ],
+ prior_user_presence: %{user: %{id: 3}, joined_at: ~N[2024-07-03 12:10:00], active_sessions: 1},
+ current_user_presence: %{user: %{id: 1}, joined_at: ~N[2024-07-03 12:00:00], active_sessions: 1},
has_presence_edit_priority: true
-}
+}
@@ -518,8 +518,8 @@ list_presences(topic)
Examples
-iex> Lightning.Workflows.Presence.list_presences("workflow:canvas")
-[%Lightning.Workflows.Presence{user: %User{id: 1}, ...}, ...]
+iex> Lightning.Workflows.Presence.list_presences("workflow:canvas")
+[%Lightning.Workflows.Presence{user: %User{id: 1}, ...}, ...]
@@ -555,12 +555,12 @@ new_user_presence(user, joined_at, active_s
Examples
-iex> Lightning.Workflows.Presence.new_user_presence(%User{id: 1}, 1625597762000000)
-%Lightning.Workflows.Presence{
- user: %User{id: 1},
+iex> Lightning.Workflows.Presence.new_user_presence(%User{id: 1}, 1625597762000000)
+%Lightning.Workflows.Presence{
+ user: %User{id: 1},
joined_at: 1625597762000000,
active_sessions: 0
-}
+}
@@ -638,7 +638,7 @@ track_user_presence(user, topic, pid)
Examples
-iex> Lightning.Workflows.Presence.track_user_presence(%User{id: 1}, "room:lobby", self())
+iex> Lightning.Workflows.Presence.track_user_presence(%User{id: 1}, "room:lobby", self())
:ok
diff --git a/Lightning.Workflows.html b/Lightning.Workflows.html
index b5c991b494..3198e6fea6 100644
--- a/Lightning.Workflows.html
+++ b/Lightning.Workflows.html
@@ -446,8 +446,8 @@ change_workflow(workflow, attrs \\ %{})
Examples
-iex> change_workflow(workflow)
-%Ecto.Changeset{data: %Workflow{}}
+iex> change_workflow(workflow)
+%Ecto.Changeset{data: %Workflow{}}
@@ -509,12 +509,12 @@ get_edge_by_trigger(trigger)
Examples
-trigger = %Trigger{id: 1, ...}
-Lightning.Workflows.get_edge_by_trigger(trigger)
+trigger = %Trigger{id: 1, ...}
+Lightning.Workflows.get_edge_by_trigger(trigger)
# => %Edge{source_trigger: %Trigger{}, target_job: %Job{}, ...}
-non_existent_trigger = %Trigger{id: 999, ...}
-Lightning.Workflows.get_edge_by_trigger(non_existent_trigger)
+non_existent_trigger = %Trigger{id: 999, ...}
+Lightning.Workflows.get_edge_by_trigger(non_existent_trigger)
# => nil
@@ -584,10 +584,10 @@ get_trigger_by_webhook(path)
Examples
-Lightning.Workflows.get_trigger_by_webhook("some_path_or_id")
+Lightning.Workflows.get_trigger_by_webhook("some_path_or_id")
# => %Trigger{id: 1, custom_path: "some_path_or_id", ...}
-Lightning.Workflows.get_trigger_by_webhook("non_existent_path_or_id")
+Lightning.Workflows.get_trigger_by_webhook("non_existent_path_or_id")
# => nil
@@ -662,10 +662,10 @@ get_workflow!(id)
Examples
-iex> get_workflow!(123)
-%Workflow{}
+iex> get_workflow!(123)
+%Workflow{}
-iex> get_workflow!(456)
+iex> get_workflow!(456)
** (Ecto.NoResultsError)
@@ -769,8 +769,8 @@ list_workflows()
Examples
-iex> list_workflows()
-[%Workflow{}, ...]
+iex> list_workflows()
+[%Workflow{}, ...]
@@ -800,8 +800,8 @@ mark_for_deletion(workflow, attrs \\ %{})
Examples
-iex> change_request_deletion(workflow)
-%Ecto.Changeset{data: %Workflow{}}
+iex> change_request_deletion(workflow)
+%Ecto.Changeset{data: %Workflow{}}
diff --git a/Lightning.epub b/Lightning.epub
index aff68d1d18b6a2b810714e8a0a3921fd6e8cd704..ce6a30d57164704b8c918dff9c3183264e45da1e 100644
GIT binary patch
delta 235302
zcmV)cK&Zczs4BXtDhyCd0|XQR00000yJ?XOI0CzAu|^OI0=sFmSPG#50=sFm`wJ2Z
z3A<@-S?(a-tlhH~7HSrMlH0fuzVj&%rE14hC6e}dvsIqesMh~>m49Yu>~;3!f=Eb2
zL;^Gbj-);14RXmfw>(6iXI~(%kgow!qDGQ4{u;UxjH^7##gsRt
zv&8lRAMlG`}(h+pTGNMl+w#Fb9(oC^;sl?Fx-`}ev4*R8
z27LD+QUT)S(c2K3%;`0iA|00
zFlH1YW_4q-@SV#_;L`zN=8CqJO6e;^?MkqBFW=i?G$Vg0iX~t~B35S-DgiN|kRjMy
z$=?Fbd~yJjeJ&S&udj#fjhq!ud7ZGak)?xjwu4Af%B4iWxSDxn4aU#?6NmsI8kBVZW4}s_@|Q=QpH-<=pWJw<2kO-SK+LR)}!UN;wx4*bR)Y
z0|zmf>XNdZjI&PE6kmKl4SDp?=TR-QdEC@7SFyAf;JsP)92C2|oH>U|*3l0wd^+<)HnIxI6(op2mHN;ZCxgCtdUyq##X2_W$*BdL!
zX>hd&cFB4s8^=LBD@wX{#;!L!{jW*h9sCKW@Dgcdt=4N9pv&>7loY3@rB=d6VpBPdKs2S(CR8hRprQ9N
zL-=lgyzazb8YH0qlER~Nc!0JXjOhyyyK!(zMg&7H8nw>IjRP%qMeU$$iiNt8=zEkW
zgRu?GpR$}@vffKy4JjuoJ{OUHo1p{Fgxyj47Au(T@aL0f0Se(nNMJ^^%KE*U8ub;q
zkv@I(_}$CrZ{EL5s+`@EK3}7wkID#-(fo*iwU9tw=Ex;x3k}fb!e&O+^a2^_9o`xh
zG6^QYT$~6M1R}M5#cCy&-WK!H97_}*)W%X
z2(F<*({js7NiYRwrlWo#Ke`BuJT)y*)Q=Ld
zQYt|xng#`E(%Jp<&xB!*s|h~+5gauXUp6&yXAAKHMK2hH
zgLsq9FA`5pGOkd!yF#qM!0o!+wGxJZ>ejmI?*^2VtO7j?b(37sOe*QF<@L~`2O42D
za?9HhaBzNsvK$>HXy4_sL26RxXndXt*|^*(oVpRpK=J
zM!X8FlJ;oFymghM9^;wIJ|WU1K`obl=WdFWZF!p*y#Pf|`qL6ocErHe0?`3(VxM}T
zD^zZ880MSpad*MK^!nK)>G#-wza;&yg8tnp$tOq1#heA(8QI>WOteY=5LCn04HE-{
z=aYK>wD9#Q7Tmwot5o~e04^E6doqYhs+6}F2W>sxHIHo&YSWv=sq)^C5V>@JjNtu_
zEqdI?64M>y6T$eX(l9_;ySLcs4kzH&ia;ZKRKczvLF(0I~YcjKeM_`Um?MmbrDzUoCGvx0V5_-VeIRX9aNP|u4Rd*JH&a%C|N
zB*4zS<27mN8TdkfDq>E-#=Sd8^py0ZGv%I~vf2nsAPn@mkY!GoD%(DNOg9vO6Sk!Q
zdfOw1IU?L4hQPE(BK|%RbZ;sAcH!3RLHzKTj;aFN-_a1k6WujQ-kA1=5L}XO_dLA)
zTTG?7K;8D`bN|_To5J7Q5$qH0?RwH(0)A65+7bSv>Q8%rQ@LAm+B-@^$@_PtsRP_OnpSA#JEPHgHk
z3IYa+1H#c>;cPH|3OvbjLsD*}wUUGJgIk(81=wzXBT^51y2UflgE}VEojiJUAOBAN
z@_qbZFur%dgUJE?D^q@pn&aCz6zbCh>KnT^G+&V@<>ZzU!qAUPcdo_*&1qfQ1A_5h
z%uEO4ljPxTqIM8wUolRqtZeeVNc)P^N@N*Q`ZmT{49>+NOpQ-(nH@^sQouG@aXXR!
z0RRAh|Nq2UdvDuD693gK+vQ>aB&-??%fq_A*{%exE0A|c9)j?
z?Qdo&xpqt{StpkUh%8Y%kDbSF9!i$7!1LJDqDs#B71BZ&^CH*;33NSI^o7zs6jhL9
zQe$eBzV4wr>Y+GqU^M}3X;f+SsEn2s>atBqVlAm(0Y*nY%a|=
zarrt(Hqzz~b|*>EIIyQa>B^|hk(O17_JidN6hw!~LOva~?&0R0<(
zOytx&XrVY&8PcCx(`(I%3Ke1oR)MUH6-5E43sJ3z;T0CDF0rzJ)s@t$a_`TX!(Ihh
z6|%x0F-@jG)b=ALAu-vBJUSPUYh1nva%*cdi{lktw^?w6$5_a%)FG3^xSeMzjioUS
zns_*w3^~`As98r&UT|NX$AYhsoabYIkQoKOR*M2l6S5UU;;=>?+*pdrkW^KeqsU~n
zqRInsqtBy*q`A66(o9xsM@4jU|CN^Rc~}M@v=m`3GXjYhfz=I}#ZadE6
z)&|MDomgP8@XCqZxrqv6KBm`vlKdOBA=L@8=mUA|GDlc6vdEwm*FZ%NHcGF5K~I}S`A!MOzLMdX#Oj;6#5Xa?+@#}Dknf!2i1<510RG_gWt|a3cACnlhMMdgG*O
zG-z2j4G}@N19$uQ(fI7Sq5F!mF0eD2f`l-6cb9OPZQ(JUeePZ$tsSpuNAEuLFnI*O
z?#yD=vL?(%;3`3IQ>YC{=OWk$swJe@8nJFwrRpvg!t|+@-N7*O!>Q&u?FH%l7?S-9E
zT=IFgib}cC{hU8y(bPwMY4x&Zul_6xnR0%&>GYo*E0$YvJa-oUdjfWhxggzP2~RGD
zCvY*M|KsB}0ZH|odkY%(D$Dhq48Bwa1qq8ot(E@razvjWulzcH#5!=X7_PKx>X4g@
zv(a#RI(T+A9fZ`4{MG|=e9DCZhJ+q<~>Nl
zu!kK*$x?28hjMy@wsRn)ZeZq9i@9zMqQO~T0q-4TDRHb7zKXm2@YLIX`ad*CD^CJN
zQ?w@u7E4bG;Wc%C^<^3{D&%51@ulh8p!CHofoRhivIl6k&!#>U3>v)`>1@DAhUxU}
zp^mz<#d~n7^y1Q`7HMbGdcZ3Ss=e!4$;x*@NOh(5xmGVa`G0X>JNgZhmGQ->;;Pfq
z55O0iuv0W%Yqy)_M!b+!Y;p)wpb~SlU
z>a9y2AvzmVhpe$EGsZqA>;zB~
zL`QpF2~{$GC~5TKUe~FdqsAHBTXa#trfZ%7m(<$2eb)z?GI=3o;-|yGWH5a;j6Y!6
zgaqy3bP~GXKWGTCA(zb1RicodIBoWaj0#6Qs8F2bA6)}w8M
zFAAgF@InBrzPzEo-|C(YPDhhx!_jzps5_@i$?nnu@hOw{JSBgO3@{gUXVpE_uJD@0
z+qI)0dD3^KSw-L?I-TLWB|NCZxF=vgMbsISpStaFU#HQj_sRyzci+L2*Z+NUc?|R%
zw<*>f)UXi-w2%g~ncIm2pL?lS4gW&$ng^3(a8TkF)G62N3zanmMs;K7!dfjCjm3Bj
z3rt00&_R6Zj=+CgMh)ILL>F@VPOCpLwLs`93P#-P{m-0PE1Ca2X>kLF(Qq1#j)7n+
zZka{6ozdk7v%P%o7POs{T65;6s^a<|@#wQz4JN}IR`dCt%gpET=`B7K$S@=>(c~C*
zK^>tkX5-Tt?4vv~R@L$F78RAY3JW-kMocIE!jX9?j72i-Sd7lb#G~U&mj-ib=c>r!
z&X%8@&3)zn00030|Lj?9Z`(Ey{+?gKYS_?rmQ>qGmy=9BCq?*!WJ$ai-aU7`BP%MB
zsjjFX8K+wB1q%}-j~|nVhty=nOQocGM1&-zeI#;D6k8OA6jbCyvmD47&Q1d3l}
zGTv!e;786fYM2yhNwophdMafml{_Di?Q2}G6I~ZDdNw}!aPq@PG=b@0H
z3otvPq=L;sn-FD%sBOIrsVbjthiAJX6G#9bhj4}$j1dIpa|3@SK?KsF<
z$_n(8jZg@4s?M2MQ#>LzcZ0x0DllTL+AcI)4A>`sm&hm1Z!SPD^DpTs)D;2FmP`d0
zY*c7Y4eSL%2HgwEF^XX&td|mJM3PI;E{E%aRgHCLOi&9Q7h)?Ldl1oB>cbkb!(
zvM(@y=W*^S4uRoCfr5@}Z9Ju{gF|_eY3WHoJ;yspu6!p$g|8St8wUwSWkppl2s+6y
zH)3FU3c@h-f%NAB5^I?rc5x2{rcO@^L-nclq*>$7XR1i0E-eRNN&}tKse)wEnIc$_
z>^}3M*c6yp^+s>3b)pyR#pw73Gg#Z|fscuQ?L7Jt-927z7cV=*ZwoJ28Tmq`a|WBB
zQUxTZhK36z>ngN`=I&@b+#db3`)m{rgXEzfTKbG)SL|Ul>?aP_mcMjm~(d{4@mwO?_s+4tSc=xZ98~ifDMbsP4V;}JnKQO-n;!>#k$7Z_0r@b?O
z>WqLJ2k7{J7@*^CGe9%W?!F-DH1ACpm=_28UkS7qPX3b3C)WboEhyHsO>L8Go13?DA!1}%34+T=avg8
zD60ACuI0M1hNaz+V}`HD8KZvt5d*h>F@O@bu(=@GFjPVV+}Q?!*4V=pw}GY&AyH9N
zq(-JWQ`k7m?sl%19#ML+ZR|scbgA81>uk|BXq&^CCxw4n*;I%2T2V1C#jI<4<=iA!
z{O;T9>pJU%)&`P!PffpRt@duIH{#H)p?&7Ook($r5nj{m?cRK4+gZR8vipdCzmNFO
zq7;{8A-y&dTX@x`6W;e(=W;Cc6hTI^;oLq0+H)bZjBg{0&Q*wTBu;dJwLO
zqK^fR0EWeevM0^9=%7`lB+UxYgw7<^J?B!L4oJm;Y9NX-yrSMr>lzv^#mF5s>AI?<
zGGBPS^y%okJ5qYxNLu^B9wUuB+%eLX+D@#UlYB&+0=sFm8bvw@0=sFmR!%<>0=sFm
zmtYhR0=sFmt#4}s3A<@-S%U1kPyMqYb8QoU8^;y?zfUn>f!GFkv7DqW9GL(uQ7UVR
z6eK!9e-WeIAvw|BGP5g+Pt%_T`gDDSe&@{0E=5t6owR^$S-Ugme!g>AVU@YpvFaZW
z%HeT2oUfHw7HL{+biNWQzt^V7GnH53UK%ZLQ)PuTN*MK9t&K|F^SwG99;bSE92bdy
z5^*Z6{m{{Qs&myD&aTGO(PS~Ynk+tz|8YE^Gegl6+oCpNR;qk75qK%?)D}VzmFFmp
zu4We(v&DFNdNrF&=PjuULaRI}3k^A!h2aN8`YactlC%+E(rQW!1|;+Pd!dsLojbX_
zlfBC5)k+!L34E=JD_!KhwUP;}(HTa6LL5u6Hfs5y^QUJnt&4kQdJy=I&*O#;uZ-sB
zy{se1mc6x35|w}GRHlY@#{uz@DnijcXPBwHl5eN@X(>ez2&l@GMQ~jIA>zGG(n?DH|R8h?ItF6GFL|Y1=
zM94fL_d9xdQNcBed=?cY8C+C_h>en!YRCpLbk4s0Jn7<|aRlgrJLN?)Vr7cDv=KBi
zbxx`_;awn5NC+p?5=@{i_*YDS=3v-;8l8O_E#}vg^Yiib4Z?5q@nU=$qVG_OK!NBW
zsjaf%9@)SsTS-%i#v^@kl`3f!8AY+pyFxG7R)@p}jR<1r!CJP+)MJBL=EG;a^;u6(
zp!?Vhw<_||3zg^!SGO%4$0ETYB-kS=Vk2AMIzz927+xuZgPF`@CFV7MDThe?AwW!C
zXSeWEvE1{V4IX~%$`GGfk?5r+DYoRZ3RI&P{5Ji3`Eh)`n4K+7X49L`mvG^iT-O&Q
zUWnX#nbr!S8^yITIF@e3kvl<=n#nXsLE&BGJ7SlVGexOmQNqKT!n!Y}v-$Wvu7hB>
z$Hvcq8Dw>~#fi^B$*BN;(`ui1(BFHbXG;~s5b-W*w5}$9dN4V7XCqBQl7p85
zG-a9{y#0EUUXE{WM(5+3#T9O4_NFDW+p8%jIeMG;Vh6%E}!lCzLq7j>F6Z}AG=Tdm8w60bLeP)iwC
zh2d;+R-(8R9G4s{FvlN^$`?Ebd^%N0U8Xwb>gvgTF`~1O?K_TZD7I
zOG&R?{^s;*Nd<-)69r05T;ZnD_rOe-7RUuyy+YF=fEw5T(yJGg?-h*N2(_
z`Zb41*}Tnv5of9HuGxGqVPt&A_y@fzT+R@Dgf=@qlwt+1<@=1fR5tO%s1|p_k;onK
z4!8atU;(}kj%=}9^=|iVo2AaW1#K
zLSO)VAm=-xhl;N|8nH~F5>XJDQ0~j&WET%w5kS6w7sQk7r5)BxZ;b+XtH_#;V3!di
zVm4@xC@2nh1cp$VODOEVA%nN1+AdZ)TzfTv-868%(VG6nWT4~it7c;Ga{F}5fXk00
zh<1?Saal1`B66otTG+;wlginE!bnk_a*;tzSG-p79dm8U)U#FB32pn0ullHsb=CHg
zl(##7aO?vbc1duu-O-Q=8uk2ITQ#qiPk}Rzgb{53nw9O+~d%q*+z(f!}R8B)5
zn<014q)sU%&|gx+!p3V7_j68MV)zk34)}LRsm3yRk~n+ZI4&$WF;9SS%EN-A5Y;wJ
zDg<4yVG(O?TKzBsc>NVA*B1^k2#h@urgkfT&8i@e$r6rMNwk;I?ckIYa67fkn4Wyj
zz{|SSFsOChn65*&ROPE`9eEe;@Oe_|zgXX9^T`>ZDuL+u^5f|Ge6|OsVm$phYD)c1
zCvLUnR3UGG*`<%%;D<0ZUR{hwH)G$X61b!=Q%==piF?ALI#b=!PIsT!-MxO3+(?#x
zyJegr&MMiRFk(Ag9wrHOy
z;R744MQIVR!~q=ro_b4f!8hwi468JMS~$x1UqI7#0QyqQj4tNm>nRoDoB8Y-J<;Cu
z+I6Gh3r*%zDp#ZV-*#fI9egu*#rO84B&k)(YV9J!873mj5w5^Ed}lWde8L3FP|KJg
zJ5$RZu{B@WhCYb^wTMb81-Y*$>Y*$+W8t$lxI%z8VTgX*Y|E;N2$nQ>htkr2B{GZ?
zk(}IiGB
zI-=ED*ix|nq;1;bfQc?cn-PhBM?s%h+P8I-G||p@wJV_uDNd`@*zqI
z>%`$a_%5w}@&;e%TujCf+?N$FE+HQk)SND`K-BxV^;;VZZeNU)eZ1l&_(oF)4?k$rp*B3XDe~e&
zCoej~N6XMW?zAh+J_kn_2>QOTT|4t_{f_j}b&%^HdY*TN-s+32DUVN&l^u@L9yg&q
zS{`Fk`SIxJ-Mhd3rFYbS8NNPrY2#MMhqyjc#;tz7QEJ{pFPc)l@Kt(25x*et{bn`Z
zJ)_1;m)<<5`|mMiL(C-y!iHj|9G=w%0cxnVWqdViB~9Y?8K@;{E$=mbSwOdSFqQX0
zq`&XvuwC|_+Z&{PHBis4*06{?+GG&?2=Ww#)j8IaAl
zyzZmUswh^e>J_qouGa6q@|(`#JO95=I_Jz!%$VPkFFK!jgUH{>{K1nH{g9AxjF7Cl
ziyw(T31zR-wy^<(ZaVlaXPykO{P@R2BZuPmb9iC1d<_t_M>Y>@%3!qx<@bsYoo}z
zK!Zv3o05)ALyI!{%J3+{+@#AkXx9Sn3r1J0R5hSoW?D!$yE(i0^MAjYO}WYNABCb9
zK8L!B#;q)VP+Z}Mq5ooF+NR3+x`*CpmA~gC`>E4RTt9m%JEKXpe&Oz^va!*nTTs&J
z0kInd*0)7uvh@-qUy|UE_0MOs^NaD~&
zqFq|D(LI{?9Vb@kf1v@!$Uij@IVesuHT@*z`J7LW5eT;l?WR2VevO&)ARTK
z2tNH6vt5$z0e`z`Zdv8Ij^K740009L0RRyI002)#LQqpLV{dMBWo~pXZ*XSBnQw2a
zHWbF+_fsI=PC!VTyDUm_b#HH{ZR(b+e|Dw4bMYbZYHVigH2L;35HL$1RMYT{q6p4;
z%=5F&aSfe++$Yr8fyfAF3peyft^+LMn6S;leSZ4Un}50=msj%?MXzWBj#jg5;clf&
zXF>4x_U03u#y%IDU_2UqAMiAGubk?m82MX)M=&r+Vgh2}rh@+kk@W7#W-FO?X~=7g
zYmKqg@p%FgVI)!MJHt_Johm^KTO0*IA<+(55c*+IG}KLTG?PS9Sk_LC=ZyVujl<>m+~)^5h|fg^SXZk_bsX
zAwiM;Zl6nzXausNrISU1q*8+grxp>{^I4e`qx~Oknij{K#kdGSIDyKhJR8JEvHUim
zJVLZ~Ys7}|#E?>c$Zze+(L{#ud(oA@O^|rio$?c0nVy7)aDLutnm*b!V?%gGTV3Qpd2Lt+{tve^JF{jT?dre~om;&iw$_zkYTZPJ@H3tH6h&O=
zW&gaJRmP6Lf476n7^T1x&2wg^q9bjQ#DCxvvOA`dKBih|k?ynJ)~NKBW9XqXLW^|2
z@pAXj!&b>Gl0B`S);(0Y#3m7c1=fd@Yk!7iy5%e;EemfMx8d!7=3Hh{ptO^sR#@SA
zmV~w}j?L__91n`M_~+5#eLMd)G?Er5enJe>#s;e+ZIMLJf09y=prd_M4e7Tae3Z~q
zOWj(VjE@ot`Hms1bk^D4GkCSo0^M5h(IT=&
zbD&n+;&A(ZB!zrXZ95vK@bIZ{s!+{+?gKs=)P2CE4;z;yuSeHrb+SchS8~
z)8cR_3R)an+?7a`r0n?LcSy=|lz1K6ht&IF6__*RaQMtKGvxT2n_sSf{qM(jBr`=m
zIUCy#c_?zBFN4gO@=Y8sm&<6`i=>*z-O*?iKUkT-3cbmxm|q4U0@D0-M%;ftH^mz$
zt7&T<&dQmaDd}|1V_E88f(qjdD4RIVaRG*sG^0v`xeO{Z3oil^*Mo+e946NpE(W=r
zlaRdU^UMe?=46pX-A>dU$6n~sY=RbW8O%X|qDHEKq*53VIQ_ea8<~@2-CC53eGp
zyPjC5ikF6Hl|ELvetZ7*rw{kPN1xFh#!r4c&boNO<>V^QiI9d)bFhv^5lxIFCgYlvN`8jakR^Xdp(zk1)2hJP
zfDtad$c*O@jpK4MuJQ@GYBEkGgSBZ~pz|P@Trmc09NVD@nMp+iEXfS0sT62bw|ZaG
z^>(+k*LI>2@PLl92R^GrYPb|M=VtZ7ls8Z+NU3Shs-+a6ks)qWK_M5o%RNo}bB`GG&Q=b&OmrWJo~4F_IQzJs(x+bL>h@6o{m0PS&IeLaS6UFwt%E_-8
z*tH632%hE?RTz{r#!*5^1F>;TC*Pk@
z!P+>YECc26b@prl4aEYKV*_168e;(C+>v7!++9J1;VJnIl*WHU#sjxYc;ID;LwY4J
zCc$nXSUX39gG6Y<230(}tQY=vi$aFyr9vC!fJ*2q%JuCu36{lgw5z_)GK~-Sm
zl)K5%DErYR6>CMy8NuX#_swd5U{K>YMqivImSlU*erjW6Pt)77uV-}~w~e_y{J)O#
ztBP?$@N|(wR~UbWrBp@}SRg&<=cha8Cab0nHouf0eh`SknyO>2bp<+3dc*Tz@~!
zgC3!@c92KkzAkzy{d!Jn2x^;~Zs$TOARqH;9$iZzqFb>*iemq%K&{>>g<+1NdWT+9
ztK-}@JWs6K@UwB7Js-x%tzhtA*?cQyFluO;^YTyLu#SI?{B5GD5_&CTqk5~*QmQY1
zO2sfl*Rn3HxO_6B8uJig7z6gu4%=#3<+7*je7Q)%ZYS)9Nhj%t-EP?J
z?diE4im!jjpLId^2UdBTg|{=QJKC^&2oN4gp9BgxL~M0xV-kVj>?BkZ8%7~cfi&w&
zE+BxsE7ef}G#q(Ej9N@#*M6(y7lh%hC@Vv5YGNSwx5ve4#}iU#7w|gA0&lD0s{^mI
z5Af=ovp4jf%bzMsiB#Fz1o4*V-ekfJ6q;bNs*r!0c!9|tX}tTvbz?L&$nwWwu*Hh_})X8t9G}RD6qvy0mIP4-WvPe$$Uu^9i2!;++m>dcqxr2-^#3{dYt(CNmL7}q84?9dXeIq<}D
zebR2{ZfxTO%}t7{6R{wiQj=!B!=ekx88N&7SsA^q7TMI2i}0>K(xRTXsFyq|8$U$U
zCF>oi1y8}d$oj>332c9Z0fV%Lp(!hYMFX%SjTrdabufA{1#UW%&c)#=aI5w|lLA}K
zP3K~Fjk#|eJ(oWbSAPPN5xEn8vjTLw+6-1DlB_tINe7-u2QMOM(_(ba4@b~e?SBSA
ztuCc=zN?7ZH`hOvKFwt#WA;Ae{?=u=f(klsgXPF8$AQ0c96Y{qbnTE)(xO#AUgCSS
z0Qnayj)K~|XnWr^%jMFOvBtK@+Ju=wRw{+)NQ(xpKf=#fQ925{gAK%ghWi8bYl^Rn
z%~8}Hv|u^h1L2=1^BTCm5#CMvk?|)rMd$zvGx7oU=%fslf
zTDrmTg){vLddBnPn{URC
zIc4v&o>t4G$W*rM<)zlW;4YYU=5KhJ_2hhp`|}z8e@e_+aP%y;SL*pJ8449W
zbYk_DqVA|8LM@$td+0dm0a4wAWQ3=5<~Ks@#J)M)otPEbu2$KT--xZMzGaoa-c36~
zS|z)QiXzG$I)yE%109rqGIZj_Jm6LeY
zj3SXryHuGI22U_r%iQ52j*)gkWuiz3i_7s|#-3+E)MAT#v8S?yIP3c1i!>r(qVk}g>oX<64LwR7#Da_uX%U;xpaqpF?uuN3EVnu$bGQwz|nY
zCuvzJeg}bn5K*qUsrCO(s#O^g_>5Qu-D!6)>IVH_)E)G@u<~iiapd6T^5pMTa67#n
zjQ$Z_@htd7;sp5J=DNg_PtWzk-IsfZcPyzn*Ktd+j#48W!ZM|-@KA^tibQ4#6|1ni
zz>gA^wDkE{m@4tp90@A3kc5eEq%O#25~%7B*2p@45hJ>Plkt-jg;mQXS$EqGBJKti
z%nn9-@ecKcD|1%D%d%xAQc8{82(4082$Q!4_F!0r@vs@#!$f9FIBzkc64$`Sd=TogW{?#6>7i3d6kl7*pW7rs8cHyk!cqb{VFE<$6_LQcI~MNe&pcA
zV^bpdyr;%Tilyg_JMz2FbA8>0>tLuQn*??S#e<($3MzxYm+6_+aHr7J*F!AF@@DXV
z9R9wC>crIoy2}TKAY&qz>K2+M;N0Nf`P7uH@*L5?K{{j%gHp
zlvt+ysQBB^jTNxhZEz`V$=HUIJB}ADuS)*RcN*JwQ5kH2*ZolG_K`w1*k;z_O>`zaBTx>t0pZ{LLThw8H#z-JZ}MkY;jP7L05T|sg)(jg0a}qn-z?pkt?{$C
zQ6=shbB~%(+@DE6?ypWj_Wg!`u-i(}8h&;Tkk0r@IywY?kk_7TTVuQ2UwrN
z1l-?{^$v`+TzZmhWLYG5Ck5G#m1r@(s)dgRo|D5IV0?>8g+YVis+y^nF!-rSF^AOK8fh*iJqpFFr=FyMxi$cA(Z$fsv=zSdP(z
z{;t{&PIcgsgBPa>{g*UhaCeL*occP4yRSkM{@?-6W(#&c1m*s?X2%h>1VQXdZe3pM
zD)N16>!&TUG%|%J*0AOWwW7r)e>nnPDIO`bCf|Lp6_#Vrb82Zj++ilm7G^7-~FsX%w2i1fl-)_}u5zLDuX2SE5~>Z|uI^5S*`k4EDof{z7R;)m~
z0xh~>81{jdXp0ShMXDra$NzqJr0m48jI3=8fo6s6603T(yJ
zu*$fCL`%sE%hSe`L1y^;RWoz0urE8Eg>YFpYbQGIyf3(VtvXUHGN*)EbcD4fx1D&<
zA2e^iqRX_yZl<{7W{SV>n7M;e&4m(Po^`yikg+A6h3#E`Qz{G0!Zgt-heR@KUp0l2
zLhfiYzct~uPjPUncc@vlstd)s02<_nG)Z1+7Vs`
z>PZ({Fts^<==i;B-u$tQ+mrVAPiVn|+-Zk4qIEi1jDNG9e=UX&PFtfBU*_rV%e}%a
zNqVGm5C4)k&@Hz!A%$DRTpK7YHx`_xAH$tl!v`NFDuu*w<~Za`l}y5K8bj>8Noo7s
z=p0HQKN&*3;F*Nrnd}8mu<~4g+@swlCtCUG?#o&EHAy;bWn2Qh
z%_WFLqe)2z$=3LfLSq-;gp>T=0fpYkgF{iME>9DPPfg$039N{5u9+!MGUlus*RB^Py@o7+?N1!hJz4%gJS?6bb#KL
zex*1t$DmRqC8WaFUrO!1-&BC`
ziDKE6))U9el!S^m3CD9xCmBKkzC{H|59k1vDCv_aNieG2i%r2qE0Wj1u7pbvifb~d
zXzZC(G~Q9^r~5)12RvPPL8Ul*u^I@9_}^ISfp&J88vd^==2xU7A4-w+zzDJ;oqUr5sOp
z|F;bC2~Rq?QXV*PC8qR7QAdd-GZ#waWscpEwFo0ANUjzxBP5Dq${tE?lQJrQTA0om
z+sV
z@8R1$DJjo&8=+IpRa+ah{4)zA;RWKED+{oR5rw07MKahpIEqDT=BVVA)}EMLo35^olq%
zbKXau@YLz-dmgVpe_Qh<4Q^GTqQVb$8n*U-#*ulxWoLb7OQUtHcM*
zx^5*3gT82wHa$Y*!4_GgQ`_L@&s`dk2age%3hW_7-lEm1eDJ`5E5X};&jK@<2d0o=
zG1kbPXQgwxibJJ6XY!PZ;?!W^aD$;*F&M{YlGiNX{jM+H{q9a^zR8h>EHOKD5;z-%
zDV>Au6F};ONrV!r{gd;A2N=a;fjLZ$()&{h!`}9*jqZ3}ID}X}%e20OPaob^-JIu_
zWV%iB4$g?h0)6V%MNR*IbqC&mczHUR0pi`f8YK{!6imYJx9{G<7V?pN8or%8RKXPD
z5QD2CqIKgcOlAAS-M9)e9@Eb6Fvtj9spk2`jLQOx)?zc^#6o&UR-?5K+!jch1;#r*
zr12J=SPzm1QQ*kY-cacgNcJDVZg>tz9z1txknHb(&z0w2VG(yFxcQ`QvLye{;OLR}k8_S)~yWnQd_gU>Xz1yopVg249=XAk{h
zkT~3zNZ%i6%$SN=dPF7qKyl`W5|Yihw9f_G&a<4>(jik00}M)r2UZg3O5LGk;2^#3
z5iIUKVCty^@A-3=#^T-%7DvZM2nV|HzW@LL|Nq=sZExCtND%(cub6YCs+EEPLkRSU
zb-gydim=H)LogRBHNF39+-RpV~r9`P?FA)nW+bQF7HxuWw&5&g7c{}rfNJiQT!^QmA
z)6!5coOGCf+qy&Cm&ys>EY$Qyd*NFvYSOU-VQbP!`uJ(maFQ}R1V*!z=@n!mHYo)y
zKv5b4f%iYVA12R*)bPbnxq_U^sgN1r5e33Yx>8K}ty{Aat#kFJ)0r`ym}@^0S?4^b
z`~&Z#Y?f$_ICPj&hN@0581%gGh5fRsPjCi)SiO>eKCt-MixR?T7NhVY%9}0f9mjKBBfK
zH-JV=*~~}>m4g=5;;=+*Au>v%N$1z-I8HLuv?)zTqr$S$*E9_rO&39X+z#47HyE_L
zWBm6-wpOp(A8G$U50CxePiVuP+${5@stD22ul?#6C0J9DjRyuI3Ed>-Noz-cy({WjEH%hflQT!SwwZ
z@xh8J=forrF=;HALPaqrN0MS9QJ88Mm@{Hfoa8DI+OmRjh=t9@@6Jvkrg;FCKxw}!
zRt+=9f3P^2ATH&Re~=Ox1Fxt*^C3e^-Be9;b#VKW#xts3
z`>j(BLdNJZj9+V@Msp9W6wLBz3f$gQa0o9XhNKwpg=6vga!WW`(4r(tKun#2uv}w<
z_Bs3_WD@EYBR7CDYoo;mFGOs*vf5abHfzv=mi>L{Km$bXHuBFZF5lXsNe4o
zdxPuxQfB#h>T?)08R^^^5n9w_pFvO+f+B)K4_NvtD
zyB6WCZ(1s<3Px1E{c@&%tU?3I!S}-3aIPusxLQ($tY*+-`l${1paSy8xx0JQ*L7`1
zyZ+tbl}emWxXEhbl##r)Nrx3Up_rE>%S+XM48vVfButc4tm%|J&zKkXnppL{e>rN{
z&`}NIt+>|wuzxoVzdtt}HA(fOx~U$OTkZ(J<|jlI>N{;7SKJen^1?S_{!Ok3cc)Yn
z^{Q?Nbx*cN*Owg(EAG_w?>ybA(``2|9^G_jG(LKNs2j?U#RTPXllZGNqE(;Ty{bF#
zez;wF1AA1#%KLAVJ7*KngDudDe_|uPgV`6b&h{I1c@?L7SB)9gsp6Eb+jkYGd#{Q!
zEU)6M`wzV*TJvD~v$QMDHq|`aj9^r`H}FJ=xqHWE95Yo$xwh~5Ta#R2*i}N5Ey25z
zVEuaVy5`p}s=@uyy*l?tDiu>swYSRtMNo@KaKuOzl@zBc<>Wd=MYSu`f1pyXL!g?K
zhJx|Xs)ApS^iQ5zsViCVOcmTu2vk
z0uKv(4=XF_qwQYFQ+pECf9v*}gGXQWSOz>i@*g=7S}{#@TEd3TT;d&
z*>V9{p(2sfhH*A7crd<~U2T_o(}uQ*^S1Bjl4*<|_=K+;s+wg~7_DHzh&vWaIez;7
z?Bwd=^tY4q%ZoM1Ta+)D6x^L43yT_V??XdE7wynNf71CM00960f5chaj^j2Geb-kI
zo`=l<JO6+Dq@(YTKon{t*K
zF@N89b7DfOSHd(if2o#!EJn-fk&*uY&Ah?5k-VA8BoXR;!(b=8xf2F=WKkv1%(K*1z=rlGs7REvM
zFMOM$;ji}+A8D)8sQ3+O%wka_CnQ#%CXlVfV}avmYi*WHn*>AN5pHm`P87IhdVwn?
zUSt^_XR@%7Pr8(B|0Au_KvuyQqF#FG4ku$kh;Gjz^ehf9%_}D++={}Igh`c%M@IXz
zlT-v>e?Q1%OD^8cCx_8t?2VI(4(Y)k5uKvkMm!xOQ6&X^WD6mZ7ONN7y|EAM-uQrO
zzNUcAzx{mny)oLbTv&_42e2$5V&ee@i&Bvl%o$w*XExQEsIXp+>D~>=6x3Hsoq
zv%Ut}b~3Yj6kho*=m-2KVRO6y!B{HkB>3N!e}ynXY#6}_W36W_OSAo!*bvyKgP;X|
z(C|kh9j)h2gJMc?IH%w-oZ|zAC%nK2TbGCXy^w2rrvqg!AFrXSqv5X?B%f%jGf7ER
ziO4gPXd3|mr(ih?K4Fk*@mUXSLyvph4#2iu
zf6{JL%x0x?S^@AYE;DbvSV7*cQ(Q`l1=yNPve5v01|tPUN*%q|pL81cUw(N*9}et+
zN0~R-i(C)Ef+U~yiW91jvmg0<$*b@T!w3kXKK?oZf1TceDPN3sbX`tD9MR#(!
zAUQYjbrs2|)t&51lJ4Y1Niw)jk_>JuNxop12QTGZ&>O*nqnyJEsfd^R;Zzs3{qe{n
zVmx{Y5#!y#ULjG>O?-7kj1Lg;vPiwV4iR^^Ma1{YmLwojj*OCJ9vGJLKi2RGe_tWH
zq#RO*s%|xxCI^p;9H|)mni!-zpX)GVFpg4PVs=g3Oag8ueGA#zUP=faG6D(s#6i*Qlry!h(@E(1^@;->CEV{6GriBVksdlKB5Q
z>X^SqI~uxF0lYBr)%k05z+ZzG`Rmfo_0jN~@Rxr?fprqSQan~r-Roxi5*1NLT=&ig
zWg&mnOQAyB1*IsAqxzIue{~++k#zsCtk9@Ix7E`^P#=1Zs$oN&0Uw~dlIe*#SCUib
zPZ&kjE^72FvaykcYq4*BO#yr#{s@tHNxi~9OB7bV#~mbkf-xL<-&!R#O~gI_6oF
zh$7P)8fo9wS{)v#)kD?M
z>s+Zi_9om+b-?d2jscZBrAJa~B=mRA_WcrnGEf|$V}s9Eda}YnH{jseFC|v6uWPMs
zN-;we0j8k7D9aI)e;El)--(E2AqmU%wjPA72M1gKv&@T1MzQaH`b-9#%n=_n)}5<%
zoXHPe`my5Rho=*|=~4lDH2fyI>33=eaQ3@4%Q-dhkZ|C6&@2U)+Ux=>c_yn0SqSow
zt)xw4T@VYtHyzff-8KlxXLKa?_epm6#Fd@vio}x>U!7!!fBPicIa4GCP+Xi&j)va^
zLm%YK@Kok&&=k)>do*<05A)&=x(kwxFcj)X-xdrlU8H9v*1l0r__L9m@A}pia|UgE
zGCT=Z6^9G8l18gQ4~AnI(#q#%dZtXZb=7q037*@clC*CxNAzC+00960#93{R8aELB
z&aW5|sm)2pf5Gm;!L=Mxlw8`Vd8zJ__Cpm_X4kL|i@mYEaP-%A#)dlx+y+*qeA!J7
zkH;QA^UO0|Ddf1B7g^Q}qt0c0@GOijJN+gb^qZN$N0ANsX$T^@uFt|ow-Iz2VJmDm
zTD?ZATZcGf#$4A8kF8L$k#d&cg!MrUpwA%Hd~{uZe^z3csu|afOvs6|K`XKPNelP)
z#POT&~3u6jy2+x7T
zb0;XnbNdmNorCba)9~ncZg1eZ^Bp{ghvGRrHJ(2i0vJM&=>-3=$Pj)brGXrt!${mC
zuBIG@g|$i|iead6N3kxZLsL5lCM(iwdyurtKoV62$xg$ggCsf#B+;QDiB1iYS4#e9
ze<4$2Xtyrmy|VBkj(Kj0K7ebjv>}?gsws-=phmhDHvPBj~BVu
zXPLqRfx8E
z%89v!70jY3{NkpCJ5(x_uov{gE_$WchSzr(RM3UA0t*I`g^0cCnX06yxV^}OJnC(2
zukR$zGW0^?k>TkeD=GBE<`1HoBJqD7^#Mm+FT8X6yay?>k
zrTB$cSF|X6m6Gbds%2~VNl5jrm_Ji
z^0>R&I85(Z;<=zN^qR1Rt9wyEfAGOGm0-O>heWG9QFB?=2=A;qq+v#o%Ki)20kgMH@yt&U6QqmOLH1Pf51FzHCfmy@{iR_p+
zGVIZ^i;A!aJuJiWblz8AZVf+4I)8MO$J|08CRUttHmRJrkx!hcEOA-~e`QPS|4Wh9
z=hCd`9hMcn(`LmB)B*`g0cn|DfXY!82;&oi8q9AlQf!J@k|>ZUj#7p~g3$#CU3y@Z
ztQr2b;Fvzdy7+%ewv}OwOCqBohjGC)!+Ob+$_eJ-6K=t0Bf<6+o?F9Dl3@4~FzJN^
z)-O~=7_4IKWg+%!Bnh#If4Se~@>tYpWU!EGPS0FrB3@JuY1fCeTauAij|FMp*gkD{
z>@2<7sAKK#G%5RDU+geAQIqoW?hZF-)`hE~DtvxY$>*?JzhIE^ef&)Hl*yDbwo>QpR|xe{n1~heBaR5kb#U
z1im)gNotl2&oDd)LC;God7U$o|CSoK^%fdtg2B!EKVXJkR#n0ZI=-duZ1tSfuYF*J
zMTqWfKQ*7J*oEV7E|Xj#rEWBzGle^{_&`Y*y9@c}!5J1VEQh?tkeR2sU9vHDfaphQ
z>Tl@#!1M6T6SnVKe@&cnYO1kH#+u_1V{e~PS*;})Fn1soH}7v}gLX+5yP^P=ab5My
z_i?l{#su$&psrTp?yccD1qxgEnMlg48+pdW>Q>;qWSo#AwHj7?dYHTae3*{b@buU@
z(-el~=(GPWb~{wczLjTd_{mfXb@AZ7j=`tfx71UQ@PrF2e>+v6wyZQQpU$n#bS8K1
z;CxoO>sd-YelLv6K~$T1krVSgCRk;x`|rHL<<=6us3Gt~SX_sh3yWFpE)gL6iC@ndFz!#0k
z>7K5tId$q(ad_RjDn}smS8b8!n0E%3ZOD{x?p51if99ppof1VZ^|XE60=N=TS}b0*
ze|WIGG&8gvCG~AwNo(cmmX-1QPSplsrRbEBHtSbyZv(ckuX-{*x+mhr)k3c}dc5=P
z>(_kLRgZ6wxxI2ke}lTdQj%{0-qmPjh1v@RF4VQL9tvZ@TREMgb>K_kAv4;A3ZX*h
z#1x^hf2INf{}#oqXk{umk9Ol<>3!|~+UrfFFTTGcWLeUy}9N3`AR09(v
zmoN(+^Ojra%o=TiQww0144GVsJ6VP5`^SL7e;KMSd^8@DyS|hTL|rS1@u|MVR*r=T
z%ELQZn46&g6EGkctrp!@6UT@B;gB5X%a-Hs^-Pi(9|=1*IF%e&%;AfRuYw);Y|U2!
z*I|d&L8;zwcyYl;(q(gGkHN4+aaIaFC14K6d*XP_F(z*1?(LkwL4s&ZHy0m62X^{
z5ya?|6w0N{o*?HGeJv=DKo*<;3&@Rr;h_{W1kt+6OpdGbq$WGbBy!QBD}VRq7WGw+
zms}r43oD>rCZJxjcOWz+GwPgPutg|Qf7L}$fYwq{=fVq^i0pQmr!XhxATr8>Wgns?
zu(S&bAyu#qfiM`Iu~Br{N?3|Ay!r4Ra;%kE5LNjUI6mEJQM=L*4w+KtD^6<PJ{o
zWjweK#9;*DY}grh&O5{?r=9+|GZ^fN$jA3RA2k0v8+OOt^Z!8yHs^i^)#0YJe=ZYd
zUrKtg{3!YLg{$N*mSC9@iOMG(L9C>ih;k59AvL_D%t{0WRBx8|er$@4^MsD`Ep%=h
zQX!S~j7*t0V<$0P3X%C#^aN0`sb4twY9_x+N;a`Xb1aiyEn0X-^$6xAWmIN@jt~!8
zexpK2dm6(!<@)$?%kbCvS5_4{e<-mq!7~Q{haGb1YWj}uL__MtWHH;Quq!V#QpE?%
zrRR#-5*Z!OmBC};4@c=q8=d?E8=E{%CXb)U#IsFC^$*F!o%^0U6VJ9XvA;VL*VX>w
zP7iQ3MqUL6I4)0RQbv*Z)z|_N?T*A6L1Ekr;HV9E*7pelTH$aG^)6x
zL?5Gj^ijvWK{hR0o2J+_2gG1(%1WxkTPdbiR8gizgMez^Jc{SdUcaajBz;a9P5a~1
z8p+umHt$eo`=a&1@}pFaf47GF5V*l_K@wSgFr;jLCGpR(d#~Zk%?J1_D9T8U!GZL(
zjM{l3uk-QNoBoBmz$mE_eUfPzA}?Hzoh?8Koe$8VEE&zlbDbW
zAjuRd&lyUAlFcA0;?5zFG+oS>hxJW~{6Vw%~K`j~pex}R!M
z6%?BS-6+VXDafZ!5YcEuC})Qd(awF(O+=$DB077Th(`NLf6^TrjzmO%4^_QXN^{p)
zcKIYVW`pkNu_W2s%?Hbml_U`5Vrp$1DmI#uB9}#h+=RszEh?{@pnsJ(rx>hsR4w8P
zC1*IJJ1y?r(jZ4_mWvd;X5G%&D5lEUXiG5sOlp*0h}1lpB}JVCb!LT&i5y)}#zcM1
zIiC7Um@Mc&e;aggE`e`Wg$oLqjyOp!_e4f?DLAK0!n5uCeL$^eD
z)9K7giY8Gtda5HFZfIe22%YTQ_uO-F3;rc9pNIFdP)u%2=zq$ZFTF|nk~7CFD(m_?clYdA?6jAI$5
z%YG(VtOzdg=3l-A(~`qOCm>
ze(D1gfAg}-JkB>({*f4uo5l5_G=t_v|3r;eX00^*f1_mlrKDkPNLux*e}5)U>0^;+
zi?<}b)2P1L38PefM)#@@PZr`}j|61U@zt#-5^qiB$Z>t>SYb7)8OJmE@&ua?HmrQm
zqpjFU7&jU5ob3IHkYKkxl12#)9nI>LqJQk#kE9gNy@J8ufG{m
zmgCq-9Rb;(KpjYY42R!*^Ua8A{kE%FVz?Au#%RjLtb5uaV5?eEmvs``jzKgep$GjHf9RZ@WfStb2MAaJzIs?T;?0SWh(U
zo9Uju!>vvNd~w=239=siU*)GKImcJzEX_B&n2^if}l_qgs_wwsr*i3b7oAb
ze+q&bH(53D6IlcwOD5ilAm_8p2smWGf3>cd4&pdI?w-EFAGGTPM%ewvY$?^8=#@xd
zG?}oBF1V}|F_M&uEtoJQ$*7nyO=ip(9Aq*jmx9R35Ge>HS|)R5I*KJy2=K8_T3Hx|
zM`$7ZY%C1WEm=%>`nJ1>y(2I5;xO)e;n0hR%}qUiu@BFCz8n6}BKD8`@V~?(f17>p
z+;|NCXFYo?3Ja%T-GQgs8UB2SIK!>>!}N=0L{5nowA7h2noI$zDc5CAR|pYR2~DU-
z5xZOwSX3sQ8kQ1mSgF^j{*7xu^r}Fy7TnSym<-jUvFsU>y)A-;GS%STGpe*qQ
zF@`ieOEQQnvt$f{rGqQ*DNmYt1g=lx==Cl+_(?a9eR2t5@9gJb>Voo|PI5+;855m5
zF5fe?6;ni`e$RTe-`nC%)z|1Z3w=`3NV6IlCffS_3XAFdqU2
zVPfHe2m2Ff7*}dZ!qG9h7Ju$joZ|w=w2*~*2eQGQ3D3s|=Wet8j4*~=p%4I@6atw3
z;jc=XpT`UU;e4Ml#oR+1e;oj##8{YIOMoz)w9Rf|Y_nS!Z{g!YihmeFEpqGR1isXp
zaD*(TN;nqSEf6{wgS2y__-w{hyDJ`z>=lnj_wsC7CCr|*;DQ%bLH;K#7VWb&7XgRT
znW9BYFGPLog{Z$DUbVzI6kI#QUrZ5cS+FL^Q<-SEEpsQ|v?P_te@Y_w*}5v+aH8ZK
z@X;*$o`3UisGe*8dcBMf*}wp_&YW3SfG_QT%S@5OdH3;90qZtK_}tCDtxt8!aehrx
zXbuE}o|Cj)<(I1HRE`{$9m2^m>i*f#V*mm>!t-yozb)_wFht
zyqA57sUf}oQ(3bAf6^@JWC=z1a-aju`em8(gxcE$L@1!E2`XzUq*xWQ(xj{=FoN)+
zq`;Mml~SP$x2lAL^nw@ggo?xo9HbLn!BSk%3D3D%0cv&wB;^nyG7q)fFhmfBiWA_vQHZ{n;P4<1Zg>FTRY=ZmvFl
zxcz*2{_(@b=d~Ju$m)e5{uC5d8o2HdCYf^+OmaC13h;3Nw=xGcsDq{Ukj9xp!4Xu3
z=K%z$Z}h9{f2e=#T}J~*{>`BE0W6TTBz#IrCQA@@sZCm%nOZy>UNA(&f>Uz&;rBO$
z8j^z#T;4Rxwe?l`5Cz1WP(GCVAD;Kz6cBGwKyN<<)T!xE0@xY;Vwr3~1=kts$qP(l
zFpA|?%3GOlD+_!ANrg4bGuM_4+|n!p!jlzj4Saw
z)J+U)B_JSSbWm10Lv{kepDGE09|vbtXKhV6cBULZSn0#nZ@?En1+;tTJvV5hEzri_
z$yd?=dDYXQ>-y1i6KJ$K?9#JWol8uCL9)=NI3_3E1cFxe}qxb60H4u5cT{!
ziWt~ke~^CI(++n~gDp7Ltr#6=pRULhN?p|I39Veaq0(4(=e&Tl_cY{{Ri2|ZkDWH(
zt`h1qFrf3?X6ETSA!9zZmtcDuQ11%+xMYgUJ<0GO(K#Gi(K#I6s}GzvqCxGAuWXWm
zH=*KJkk3)(olAiRcsEd{;vh%^_zsn@u1eGZe=KcVmySZ`m~f9{TvuY9Z?WJfh?ob<
zi$l@9GyFwJdCZoI!|mVD$!A-Q!j-=kP>I2V2}^$j9tM3S!10=Z#RvqDZ&fh?egsGg
zsC8!+EFI^}mc7qGWKl7Q9$~~y4>LT}#}ChYZbsbdeTIWad!NzMdY{qD_C7zmU?T;D
ze*;Is#!~E#=gwp#J1fCy;kskwHTCB{_21OZkW|qb`GFSY&o-C3hd;I?lW^o(=A-ZQ
zlMd~b@0sv-XPj*^In?l-;eRigY{GN^|JsD<1M{9YOb7np31NDu4BHw0B4IjaWlo_c
zzUB*tde(LrYhl}Py6ftW8CKTsrJ#vyf7vr1x}N#)dyU*yd!V0$qpVV%^rOKUy^34emWBB~Ru#hpP8A
z7%*X-sl>J}Hk?7ROm|vNXq=T2f_&W$W_k2(%-9UvXaq(3vese>)nw
z>SuWWOYD?d^^suBWjB#3t-rP?h7wpas-VzEueRJewlV{L_UgRyt^#LDfiVTsR&;|6
zTqJpw-sx3iU5Xz>1f;r_-*uwC6Q2F>(T??@QL{6A9W(z200960#93``<2Dlh?q4x=
z(cT@fj%C@|BzImHX_8%Rdz&nre|;%X90FPzTdZkPB`Le^ukVnQ-_B0fR+~BqtVANk
z8P3D!nHkG*y;lSJ>2gQ}Gv-xY^M>GZ+?dpXY0erMPg9hy>Q)z6?{%BpP3Sh6znGlK
z#YBt0*?R9a{|(b_(>>_by3MRjpM~gk1@B!e`40;ME!dfY6my~GFjIOwe-vtFKo=4i
zJm7%rYeJG&1XMGBB2D
zi<&G_zhGjknb3OKawgDae`P|`?NAm2PhZuiapSbnX~a?7X+)=ucB{VFU_)z?>x~SV
zv(iUyX~Nf!&&$*lwGZlF9qgZ{@yY2)=YPrx$^C4=Ke+gE^cI#z30IU7~
zzzPvaGA2i~sqOPUW3Xew^F`q*EcQqo{6o0LAuEK14>SW_D-E|egCEoYZdH2duH}Ug
z#0Raw2dzy$cu#TR#u6hqQc}6wq>>Kkh9L(Lx;W{1Zg57^-!DKa8^#cY%~xXtBO(i9
zPHG=AZXjdE)7$_he-4S&)DXV?wNUmyLM3BIHC%@O%TXDda`KjZ8|bo{}(Y
zfh*mzDZxpmL{?o4T$WJQm+xe;AxAW7DeS61Jayp@CEP~4=
zfr8@S|9JcGrhj>L^YH$r|Mu?s;r{08?)Lh=+jOIQWN)J6e~^y~%?1MD=Jpe90!4tO
zZg=A78+UP@?tJ^_yZ(`01pOgIznu?Jas7%Ix|*@fTLvx^Pb
zTrL19?=wVe+<3CZ5~R(6%(ui$C-#`>#G4>Se}N-f9wsOYND5=sg#XUmrg|%a
zR+LZGguqQ^kP~zcHIhTstZ7}GpOZE2@+4918|ba!Mmkpgs8P;1^UH&l3^%Upi+u3ucV}y8jmuc6i|vWB_<6;
zi_2i9oO$&pNhLZb>aU9Y^ML#aC}?c(;;9_6l-x_`tT)4z4EpowKfAz3dAb_3c2!mo&Fu(N#MYZ3z9XR_lwXZ2uWl?wtI$pt5}cDm#av
zvU7Y?u3^!2@_bVqSV8$5)s?PsGY2+w-$)G5f
zV=h?YyNzYn(l;5Y^r6Y$m3>RnW)ff5sSGz9j7Lfl#|{eLV4AB!ue(P%YHn)fTVA-w
zFky3$NbXogoZTR|Go@V%C_{}W;k^}$=JT^q!bkB|h4ls{r3wk$x%Jk&1(5puXGAp@
zmx(A`D7f$St}07ezR;A~yU^M(;YdxX
z#hLgopQ7tw!m^{e?DW8lU;uq&iG_DcvP8ka6<6-u3Z_R`ThC;9$Zmbo9LoJgLGQ;x
zTE4&H*)9)&yL<_8e+F4;!!m#+n+>>gMy26e?e7c4&lH3
zF-9faYr#5$E!seCe$6-0{{R30|NqQc*^b*b6n*zsTsT1cQdx`Tt@Rj9Qltpb4GH>G
z6a_6&7Bdp5aLA;*2D81WN+Bq}jtT*Sb>Q`~HUM
z+^k25DE;3n%0FB21`GW
z@S2a^&XSz)4Nbi`?6{)~2DjVE`+BmYrH}Dy4+c-@6U|7Xg`_F4l58jto&v5!;o^bu
zObo8VLS>4=kAlSvkzj9MBcb+J#-8lvCmp?YHvD$J`e3KJ>?!vM9N1x(Q%S*8DbcuG
zAStQPhrmgB>Ohgfe;2U^E>eol1fA2tPRPfs5IaZ+-x39hBr2!MJ_Ax!_SGB>@OO#}
z*NhZ6Cn#E=i)eb?X*A4SSY9rUSn1BaL?_~lHAxE``<_9`-h286Rx2Dnje}qQk%QPbR;?#?}rWa?!Z?}oJcB;$3
z!bkA4J5x~4JgF-a+ucG;Qq>O@gb$>}dF1#O$*cm2*>5L?(h~
ze{56hREF7r!BP>+W~o)(=dt3{z!4KdZKTyHn;!N8=WJSw)3imLW(Se!+N^xt?$+Wo
zI}xX_Ev1}v-ObtXJN8&8v7L^6T*tVEQL18CHLT61Z-feJ5CknCnC=fV=$eVYZg*=C
zOpiej%v&Q=*GAjf@cTq4o9DR7kQgmWf1+7}Dxl1|#M5lr$5u5EDRt!1k|d8-OX}hg
z4nupkX2aQhFqW}2!0DSj#R~_`_;j+jRb|_KhPzbH
zsiCsLx}n8BZR;h8;lxd8`wT}@{$eL-d}`f)D$V^SsuP2-tyMEQ(5Gv+>vg+Zf75Pq
zLc3Y3_IB;koDIKQIghpV7T0OH^!AUBnCldUg8g4JFClq{=PrzPVY;ct;p0y|(Lbs4
zoyl3gbA*t?f1JTprNc$LTO;J;uhF2rbm)rrv*C9U=694Qc}b+x+NQnZnmCG;rXZRs
zNQowOjz>@$i`1sX?AqSUzR|lFf4fHS;;cLKRaw!s0=r<)(UJcF00960#97;p+cpq=
z->)DXAaAlRzO2pMf)YdgNw7GU^cEw4pt
zhQq@%XGU6ZFB54B@@>oN3R-tVU)n37AD0ME8{_iM)Ge-zT8Pq*%F
zhJMz;&nmwg=3;e|JxX4hOj$NeR0^vH2$>6sHl|=lN{C%n?+vN>v&NRb-keH1>uRoJ3Q}lQT%%rwY%-kKg?rmyBkrB@N)?T
zjt@?~XmH|cc7|VW5%*+jKNRlWfh#~(c($N0EUAoDh4`0~>kZG$VBpToV6fhQ{QFDk
zrwLhm;S5uirP2*gf94>H9Ll0-%L-zf8D5k*u=&d1M5}@cDeP#;1;jxk3G)$>iEd;*
z3c@~`r^|j~NNR%gy8RRJuxG;M5OI{-f2oQR`Qc}UYoADeZaj)4QYzAQ*bdwMgEZJZ
zj|RKfrNMjLO1%LSmw)DbVOWU|zzE=aA1c`f`MrV)8selAe>t3Vc44Yvs=*ix6Q(Wp
zLEypD3$#5&pE5wt%<`ZZHm83j9vP(TTyZ?km?X6Z%6Sd_ifa5uJNVro>1au|`0doK
zJv{HyBpt0un(Xc;=_T@d=K-~M^?c0=+_)c-v|W^72r824O49DKkE?w~nM9wzspP3S
z!v!_N1v|(^e;S<$0xsFO|NIA%Ym!$fdXqv97SXvnR0eOY6c{rWMMXnrg3vh=9Mcrx
z3+%%99JubCcWJnWn{W-|qi{VnhwKc$8eHo=#VG9Uu
zqOmyd)#AK&6cosr>kU3to*kciad42~Er1M;iq2Evf4(#PI-)a8mpT)br_~}MG+51(
zCuTFub5$`$wSkr2L`a?sO2tTUrriuBw=wY;UH(U@-JYw|Zm+G>9>KCPSc}n0VZyP7
zHm>faDE=<&2ReaD%6c`-mErWo;5TS0?&EHK=DJ&1;j1ec_jdtIHFnuc$q{9M%B;$N
za+S*kfBR}s^SJ#-OYH}sq5#*xElU;V6w*Bzp8-}VHwJ8*HG{z*b}$&kN5~>rANJ@R
zqS!m{(j*aV5kz#1AUeTW1hFyvid8A8~Yc7)vf$AWOgBCXquGHExZep_n
zx6W>Z_%ugd2aU?!O^-Pv8JNSS(+$h*ux{#v2O427qMFDMic45WfBQ;qZ(yaOl<9^*D>2J44zPKD%83*wtAF?%lvYI~0
ze<2BT%#M(!4RhiiGIaR_;f(nht51eo;cN;yK^##{jHHY?`Ji_V)AJyVYhdm0@|FZX
zH97ALznTO#3+aSSO%GV&=L=@JMr^rmYr%0F>w66Y7uOB2c(=2#>{t+N*&H9GD#uG3
ztq$DOrp>*&AwD=`$XFY;~&A-ZSA!^!9)tpv^x_
zE8oO^%
zZ`4pqp*j(&(#)~DDRBj=eqUw^N`iHH(D3C?+>h$aw#!PZHc%<3Ddh~-DuyTu`4B6C
zm3C=pyI0%pMMt=4E!BfFB>sVUm*%D|i60!7_@}-`+ZlcpiT_xi#2R?f5s{oNo-kVHic4M=JvMB
z+%2!!@9(}~s!dBJq$R?9{k>B54XUT)ss6gPhE39J=2Xykhvn!o=800960#93=^BDoU%&abeT4|hgd9t|PDRT3#$W%lOoYG;(pe`BSqRpjn2
zXm8whU)v4g-*1)8BS0rhdKaN&AVb@(ay?F+DoVvb{lA0~SQ;~DxUxKPLaW9FXPJS?
zWixZGu>bCKrov@q+)i}f`BZ@Vs5(+iGpB@_c7(Mh*iJMajG9;P=txj#O76lv9${CUf!4K8JLz7>d|k(
zO=9)P2>*F2Z!&HKZ)GA)L0vYTDWQpa2`>Znq&Hh|wc6<5$u+P3H|w?W=Xcg(8@U%9
zT6opC=wv;7&HDaYNygO_($=7R;C(7K9Pc7O24T-s@8c_Z1>LiJf5=kqcp^o?EO3)#
zY+`iItTU)PyGV2jt22c{T~O>Vw?E%pbm++ybDB9j!y9YEv|^92u#Bse&A7y{Xg9uR
zLIQJ{uxu`*WK!h9v4R^XxLirexl1zogHFqU#V{3$qKoMXn`@I=_Fie%pl3N+08d15
zpwbTv5A)~d{1KKHf1rJHzF@gFzzQ%EZE~($&9Lr|eOUL$o3O@zUnpH9cfkJ8F#}^z
zpB${^Q?RVGq=Ns@whPTBXo9-Z2SNH^OZshI7>pTjtFO16ufLI<=s%`ZXj=u6d_f-w
zWsBe(v;wm^M^o9v04Q5iqi(QAcf6bCAs;5d?ZoTnQ#ZwQgY)n
zA?6khD{|1K!3%xZ?6Dmv;@9>t2cZLU{>xsHef~@
zz$CfVfXVUTwAJq&c$>ZD$GgNeiK-5e8^vP;ozjA_1X77s3e{fXl`!ll?{JKdM3)NV
zMqnNqK$zone>Y0L24WrXoDejn<^RFun8kn4F?OL6j51di^+IVBLTR)gO3#z>{Lm7$
zxBMhYd0iB8fhI>tT~-aWc3jHGmI1`My7<+P0-{D+h>ChJNKsPa(?8=5eO$_v8L*{v
zWgzW3jtf4`>`5;U_|;Suv22-~rqBB(D=
zJqOB%SPByU27BudgIR{JfKhh?DsN(MmHUnjM%^tidV#$y(WU=3FzTNcjIO2BbH>vg
zi#z260>>IjHt~SON9eR}ZNlWI+H~IC3drlyY2<2{1rk$pE(#(TMd>;ioA~DIBI6SW
zW(kYCf9llLrWds7y`qhee;~H_h~zLu6;?TN427bgP*jb#YmR?tnpA8!QB&}p2oK+~
zEYd~%o7m4f%!o{KreH1!f~II_Fj&^8KC<^S!O7Z<%HHAj*V``-pYJ~X_vXhh4
zJ^Xs}{o(8V&D|wwzv?PL&4ke^M_*wlfp^5}fBPZ8vX@~q56&^XEJ)84nALepdc0J>
zCQ6Tc0V8|EtuXva%;;pHjc^OfM{G7q>}{wEod)><>QL
zu%X^OTlFtBtHWqK3UqU{jmK%qu0P+hZy3U!^a{WnMRE6Bg2hlxfPF&H&InObf?+P}
zYS0fF^!Gw@2Y?T4Gb%Qm2!QXPkQ^;Fe~Wf`<{S;fX1$${|3S*Rlib}_^oEq)T7BF^
z?zW@u?|(6lJCxE@Y&enQzZRI5SVXzfYLV;GK6fNM3;}(xEvii!+Ck%vBO~e
z9M7Zit9U+m8=enNi|6-cQE1~fQ#%TPFt>Z&{t>dTSwdY}(+y?5yN%|bwUmA~e+$lt
z#7{aX5Sc3T7?nXr#b;bdKNlgYQ&akI96F8hPNzXVjtzZ3X%RRm-W=s3?F{6KZf{6E
zI86F4`_czt1~)j{t7K$UF~OU!$GYSTtg1hRo+p&mW#i*`yqpzsKZ6yhy0$e(&cnel
zD7DQq@AbranHe`}uuRa&+rk?Nf6*getl1_SW;%t#!eZYvqro_!#rEL)a~VrvGgO4Z
zjOh9D*5njV&GG7+j-Vz`4FgaO`@3F2pT|Njc{XP1x*@I0&I8Xl-_?YGdZUVgT+g6do4S&RLGrLdaxnG_LnuZq&p*xzcFOCaf9$wo!^z6)
z)NpJQZ=`q-
z7z$dXEiMwNl9V0o*YA+@Gge$jm|>uZT#3(nkIp%lB2hw(xvp!`NQ8W7q;*2Ipp95C
z#^rV0>YUfdqm~%g2pP4gznF|lvg~O2qpgqMibu{yE%#tt8@1vdfBxplc$A3oU91*l
zipDYFS}RQ!F_(lhVTGI#V`;)krqw?@vLw&uOhpe|e>W!7pa(Ok&3alcFmaa%c3q!$8|}tLqucKG
z8|`kRdsSb>)gT^NQX}S+VZ^!*{Avl`Jl`)?b1dKG(sw~8LH?f{|26M6+s%u=NrP^a;s9{AOai;e+NZs`3fovr5~n=S{UGk
zP-3Z`aZ5DMlo3|xqBYS}MsdJ)Zn!ozg9dqq#>*jG<5#Z&Qr3WX5Uhr*cK^a53zr?F
z-z0vOiAcly<+tIXJtdMah|Z-UR5C2bYQatOnAv~df6oSe|DFx{PjMXp5XDr^kki57
zNC=d4I2{One+iS7!yr5aS%3$SAn`AE2?cu;#KznOkbKE`&Or_d1x|7U*pSqPGde1o
zWvtZ>tkvGh(wuDaKbj5fTx=X5Za?{&;(Ldw+lP`uE$
zU?6h3AYsP{Ab%7QphxIFfEVNcLz%Av#`i+FrG$fxq8&>d&-XjE5)O8ha8Ry<%T)JY
zhK&B%k%8O?w+6lYWs`gFpHyzk8NyIGQIBg{5IkXyynceOf}*b8*XO#jP2XDR3z8yt
z@P`IJB2E;2g2c*nI}A`99)Mzh1F2(^_k6!oL$SXD#ee=mQ+D|>Q+9b?Q}$*F8fRHt
z%}_!|CQ=zU)oe`Ln
zIiobg9dFraO(NP;p$!bLAv!=`y9e;fCD8CPMP!-Yrt_MoLyIZ=t<)U6T
zd6p?{iQD>W+LX&Y*!!7+Jzd`QXEzegfU*=m1%&`$Z>zp$y@1}{SES%r{VeHlCMg(Y
z9|k5%4`G9?neSqh`|hqw)8iJY?9xoiIJR7pWeMOHAJ6Fle+>E
zynj&uErlP2@hQ!d$~^Z371;(Ehc~bWuPe_zijyqrb)GtI{TWIsr?Ry$
z4M(hQVpT4=^G{(*?kn@j2uIo%|sZkge^iHeU|w$-2OPNDB6+S@x=Y
znveJIuN`oR;E$wn=UZp-V-wXL0JvPh4}V|T4fLbJKAdHzjAl-hn2N$#Q%Ywd+M2IK
z{EszQd(F=x{(oS7nwt#pbH^pC(?JqZIfvv1v0d;9G0LAJq4WVc$*{AENE`%p9UM~E
z?ph@~FDhC}`<+@{yW8s8d8TMt=KEOE-D`fv`k8J%I5@HLg-ds^UCg;PXjpFtnKM<`C_ZYmj{LY58c)nSG
zr*da373c2nL1~mz4Z=f1QUT=_?O<0ETJ$9%zG!xjqedtQ=2IXv%!<3N$%0~!52bM3|;sK
zvBE1D^CSxg_YVRute?Dq%n+9A<;=^^LOR0rKL7v#|Nq2U{d3#65&d0%1;&}V_A-{J
z58JX6MQ!dQ$xYMRy|mY9JAXGBkc32>NrHzD>6A|Y_r3)vOR^YSW}0|B7DprqJnX)G
zy9+7%yi;Y|h#vb}CbVE2|HjHZXPiw$G0l}_YQ`qUYE{msrC73=;MQqjCQ*HpC906+
zd=g>&F*Ax)xxkdqCQ&t=xO_Uv<#fqyk}>5pn{bwCF?(^8SzDQBQGYa-Hgj|j_@>LmCTKystYogK7biMqQi*uQ<9~DmvUflqgM10Du>KMycjK>KVxC;*YJNP4fQV3O@v9RU%h#J?vSclrmzoDmlYH-Zg}rbymtTQz_b5
z?6&sH%amn;r%Ww`hQ*rqdKa8OSRTKCfzv{C)uKC-xpM@=uTW~uD{@81Gy}raCANcs
zt`Mc=9z-xuUa=)?z!n2qbTMRwoNGUz=Q$n4xk|2ob;^qABpWfAzBo#NdM?uL>BSLC
za&F9vqk3muvN*PVH0`j>4xTi;kda%uxh${!Sd5nIM_T&(-Qox#DtR}PX)4MWM^-yx
zL?r#>WKUd7#ed87i&p#wH+&lwgBkE>+L=Vz2%mLqe&dRYO%j!g^-HqEVwm@j!Gh6J
z>1&}U5sjI8M>LII^n2&MK|Sh*bC+elVkT2d_FAcVF5YEASmQ1Ij_1O_840G+0{gL&
z=S)>(H3J^AOYY!?B$s$(NSiuZ%%!nVsx-I=1V+pv@PA88vXGp8|CgT*Vf5SE0X7(q
zPL8He=t5@PqF?RcnfwjjIy=<8d&57Ub6?R?&942sAvuSwxkdo-IENOlD&ZqwDPjo9
zHS;zugw0fH+L`Wj;7y0i#&r1qGrtxrm4=p0Aw9!f55MD0H4f5=xkm==56JH!cph
zu{Xi>F@NJJg}lnGtXevBa2gysyzS7Tcj#i+?c+};gJE~rAD(pkxN)d^?|J$2Is4y>
zVXxl{EC0;8Y_s?l1BUplX$v!ghoeLHwKx3p?c^mb)l6GFVn4d_uTD6@Fj$nPP7yrM
zp(L0`7A$ebqVo6wUGTaiZmO*ni8qvzQH0#Ye
zKb-X+m{7J}c%+0vs?(Suu3rB0?d8kw-oN|dU*Es~(>Lpcf}-pCjOB`wJjyX_jhRHt
z%A%SS5D07#2_#Pq0|}N~;+8DLafcqJV#Zx=S;bd=0wX_&k7lUhb-a_F_Vs;ysI~Wo
zKYxn8gQtcSRN|(>a+%Z4DOoe6Q&f16ei)RjmU5HD3R$34^*J~jk3Ct(- qcN{$NRO
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
@rEJQnBcjkBt%AtK
ztAF0OseZcv!$tH0h)6wK3gPecyv{(J7*|e3nJAW0tHQ;PHTprEb8>{#aP2+B1%DRR
z?yVu-G=3l|7f327Rh+@$G#xsEx2`ScFXZoT0g$JU=>|jC87Xo1wnOsZV
zL7C)*$>4?SPNC3U?DrEz)S2yaVh5=19}eEd+TO9xi_Xl|!L@`?VBVpa+`-{@4e9RS
z*gNvRr`)kU$_|UU<=wefRe#x~-fS=$jGqrKFNc?1%q~ycEPB=~@?L|p$WtZy5HP|e
z*waidz(9qt5sQ&hPJVoHHSyw3$mDnUx$m<&Pbj{`84}ZA8+8&^D6K({hYyhbJlfu9
zY*fVzvMVEbg;Kl
z#`QYTJM=(M;Mi?RAVHMfo}sIn4XH^bpWe8HI5(S~)PKO+|tGZcq{nNI6qTLdy
zjgwI-&AS3uH=s4Rx(nwtMRzAxC$`-WUVpqk+s*gKM>I@tEXnv{Lp>iWs3nj^32hGr
zq+LR8sNzw%Xg8FNhJTkdl;LrBf$44>up!yZ&~1=fkff;6S7&&qxuYY^<1sHW9vbKu
zr{34JM00iF&|F;{pn1O)zf@$HNZn;BNw4FB>pxDY45yVJ=HgB-?=r6CUF~x>@8WS_
z%m;V#LI;4h+Iof`1@`Il`|E^f7^EP{tb2=mS+g=-_k7pV0DmU`({&ErPgb_RA`H-L
zb*b0dyTwGQurjBXsz6&oT~7_^s|Zu27L2Yoslo6q9(ylPiIHfOvLVfL6!=%4zPx61
zE#TY0mbaki?iw491J}ITzkPiZOJ~fg2G>0KA;`Q2`Q=?pC=-7nJGr`_0Kax3rN&aC
z4QoD-zHdiiUVrk|jv0H$j31zpk?V-}j&PB0hErc?T)TG