Layer Memoization
Layer memoization allows a layer to be created once and used multiple times in the dependency graph. If we use the same layer twice:
Layer.merge(Layer.provide(L2, L1), Layer.provide(L3, L1))
then the L1
layer will be allocated only once.
One important feature of an Effect application is that layers are shared by default. This means that if the same layer is used twice, and if we provide the layer globally, the layer will only be allocated a single time. For every layer in our dependency graph, there is only one instance of it that is shared between all the layers that depend on it.
Example
For example, assume we have the three services A
, B
, and C
. The implementation of both B
and C
is dependent on the A
service:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3class class A
A extends import Context
Context.const Tag: <"A">(id: "A") => <Self, Shape>() => Context.TagClass<Self, "A", Shape>
namespace Tag
Tag("A")<class A
A, { readonly (property) a: number
a: number }>() {}4
5class class B
B extends import Context
Context.const Tag: <"B">(id: "B") => <Self, Shape>() => Context.TagClass<Self, "B", Shape>
namespace Tag
Tag("B")<class B
B, { readonly (property) b: string
b: string }>() {}6
7class class C
C extends import Context
Context.const Tag: <"C">(id: "C") => <Self, Shape>() => Context.TagClass<Self, "C", Shape>
namespace Tag
Tag("C")<class C
C, { readonly (property) c: boolean
c: boolean }>() {}8
9const const ALive: Layer.Layer<A, never, never>
ALive = import Layer
Layer.const effect: <typeof A, never, never>(tag: typeof A, effect: Effect.Effect<{
readonly a: number;
}, never, never>) => Layer.Layer<A, never, never> (+1 overload)
Constructs a layer from the specified effect.
effect(10 class A
A,11 import Effect
Effect.const succeed: <{
a: number;
}>(value: {
a: number;
}) => Effect.Effect<{
a: number;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({ (property) a: number
a: 5 }).(method) Pipeable.pipe<Effect.Effect<{
a: number;
}, never, never>, Effect.Effect<{
a: number;
}, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
a: number;
}, never, never>) => Effect.Effect<{
a: number;
}, never, never>): Effect.Effect<...> (+21 overloads)
pipe(12 import Effect
Effect.const tap: <{
a: number;
}, Effect.Effect<void, never, never>>(f: (a: {
a: number;
}) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<{
a: number;
}, E, R>) => Effect.Effect<...> (+7 overloads)
tap(() => import Effect
Effect.const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>
Logs one or more messages or error causes at the current log level, which is INFO by default.
This function allows logging multiple items at once and can include detailed error information using `Cause` instances.
To adjust the log level, use the `Logger.withMinimumLogLevel` function.
log("initialized"))13 )14)15
16const const BLive: Layer.Layer<B, never, A>
BLive = import Layer
Layer.const effect: <typeof B, never, A>(tag: typeof B, effect: Effect.Effect<{
readonly b: string;
}, never, A>) => Layer.Layer<B, never, A> (+1 overload)
Constructs a layer from the specified effect.
effect(17 class B
B,18 import Effect
Effect.const gen: <YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
b: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {19 const { const a: number
a } = yield* class A
A20 return { (property) b: string
b: var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const a: number
a) }21 })22)23
24const const CLive: Layer.Layer<C, never, A>
CLive = import Layer
Layer.const effect: <typeof C, never, A>(tag: typeof C, effect: Effect.Effect<{
readonly c: boolean;
}, never, A>) => Layer.Layer<C, never, A> (+1 overload)
Constructs a layer from the specified effect.
effect(25 class C
C,26 import Effect
Effect.const gen: <YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
c: boolean;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {27 const { const a: number
a } = yield* class A
A28 return { (property) c: boolean
c: const a: number
a > 0 }29 })30)31
32const const program: Effect.Effect<void, never, B | C>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<B, {
readonly b: string;
}>> | YieldWrap<Context.Tag<C, {
readonly c: boolean;
}>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {33 yield* class B
B34 yield* class C
C35})36
37const const runnable: Effect.Effect<void, never, never>
runnable = import Effect
Effect.const provide: <void, never, B | C, B | C, never, never>(self: Effect.Effect<void, never, B | C>, layer: Layer.Layer<B | C, never, never>) => Effect.Effect<void, never, never> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(38 const program: Effect.Effect<void, never, B | C>
program,39 import Layer
Layer.const merge: <never, never, B, never, never, C>(self: Layer.Layer<B, never, never>, that: Layer.Layer<C, never, never>) => Layer.Layer<B | C, never, never> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(import Layer
Layer.const provide: <A, never, B, never, never, A>(self: Layer.Layer<B, never, A>, that: Layer.Layer<A, never, never>) => Layer.Layer<B, never, never> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const BLive: Layer.Layer<B, never, A>
BLive, const ALive: Layer.Layer<A, never, never>
ALive), import Layer
Layer.const provide: <A, never, C, never, never, A>(self: Layer.Layer<C, never, A>, that: Layer.Layer<A, never, never>) => Layer.Layer<C, never, never> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const CLive: Layer.Layer<C, never, A>
CLive, const ALive: Layer.Layer<A, never, never>
ALive))40)41
42import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const runnable: Effect.Effect<void, never, never>
runnable)43/*44Output:45timestamp=... level=INFO fiber=#2 message=initialized46*/
Although both BLive
and CLive
layers require the ALive
layer, the ALive
layer is instantiated only once. It is shared with both BLive
and CLive
.
If we don’t want to share a module, we should create a fresh, non-shared version of it through Layer.fresh
.
Example
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3class class A
A extends import Context
Context.const Tag: <"A">(id: "A") => <Self, Shape>() => Context.TagClass<Self, "A", Shape>
namespace Tag
Tag("A")<class A
A, { readonly (property) a: number
a: number }>() {}4
5class class B
B extends import Context
Context.const Tag: <"B">(id: "B") => <Self, Shape>() => Context.TagClass<Self, "B", Shape>
namespace Tag
Tag("B")<class B
B, { readonly (property) b: string
b: string }>() {}6
7class class C
C extends import Context
Context.const Tag: <"C">(id: "C") => <Self, Shape>() => Context.TagClass<Self, "C", Shape>
namespace Tag
Tag("C")<class C
C, { readonly (property) c: boolean
c: boolean }>() {}8
9const const ALive: Layer.Layer<A, never, never>
ALive = import Layer
Layer.const effect: <typeof A, never, never>(tag: typeof A, effect: Effect.Effect<{
readonly a: number;
}, never, never>) => Layer.Layer<A, never, never> (+1 overload)
Constructs a layer from the specified effect.
effect(10 class A
A,11 import Effect
Effect.const succeed: <{
a: number;
}>(value: {
a: number;
}) => Effect.Effect<{
a: number;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({ (property) a: number
a: 5 }).(method) Pipeable.pipe<Effect.Effect<{
a: number;
}, never, never>, Effect.Effect<{
a: number;
}, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
a: number;
}, never, never>) => Effect.Effect<{
a: number;
}, never, never>): Effect.Effect<...> (+21 overloads)
pipe(12 import Effect
Effect.const tap: <{
a: number;
}, Effect.Effect<void, never, never>>(f: (a: {
a: number;
}) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<{
a: number;
}, E, R>) => Effect.Effect<...> (+7 overloads)
tap(() => import Effect
Effect.const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>
Logs one or more messages or error causes at the current log level, which is INFO by default.
This function allows logging multiple items at once and can include detailed error information using `Cause` instances.
To adjust the log level, use the `Logger.withMinimumLogLevel` function.
log("initialized"))13 )14)15
16const const BLive: Layer.Layer<B, never, A>
BLive = import Layer
Layer.const effect: <typeof B, never, A>(tag: typeof B, effect: Effect.Effect<{
readonly b: string;
}, never, A>) => Layer.Layer<B, never, A> (+1 overload)
Constructs a layer from the specified effect.
effect(17 class B
B,18 import Effect
Effect.const gen: <YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
b: string;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {19 const { const a: number
a } = yield* class A
A20 return { (property) b: string
b: var String: StringConstructor
(value?: any) => string
Allows manipulation and formatting of text strings and determination and location of substrings within strings.
String(const a: number
a) }21 })22)23
24const const CLive: Layer.Layer<C, never, A>
CLive = import Layer
Layer.const effect: <typeof C, never, A>(tag: typeof C, effect: Effect.Effect<{
readonly c: boolean;
}, never, A>) => Layer.Layer<C, never, A> (+1 overload)
Constructs a layer from the specified effect.
effect(25 class C
C,26 import Effect
Effect.const gen: <YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
c: boolean;
}>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Context.Tag<A, {
readonly a: number;
}>>, {
...;
}, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {27 const { const a: number
a } = yield* class A
A28 return { (property) c: boolean
c: const a: number
a > 0 }29 })30)31
32const const program: Effect.Effect<void, never, B | C>
program = import Effect
Effect.const gen: <YieldWrap<Context.Tag<B, {
readonly b: string;
}>> | YieldWrap<Context.Tag<C, {
readonly c: boolean;
}>>, void>(f: (resume: Effect.Adapter) => Generator<...>) => Effect.Effect<...> (+1 overload)
gen(function* () {33 yield* class B
B34 yield* class C
C35})36
37const const runnable: Effect.Effect<void, never, never>
runnable = import Effect
Effect.const provide: <void, never, B | C, B | C, never, never>(self: Effect.Effect<void, never, B | C>, layer: Layer.Layer<B | C, never, never>) => Effect.Effect<void, never, never> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(38 const program: Effect.Effect<void, never, B | C>
program,39 import Layer
Layer.const merge: <never, never, B, never, never, C>(self: Layer.Layer<B, never, never>, that: Layer.Layer<C, never, never>) => Layer.Layer<B | C, never, never> (+1 overload)
Merges this layer with the specified layer concurrently, producing a new layer with combined input and output types.
merge(40 import Layer
Layer.const provide: <A, never, B, never, never, A>(self: Layer.Layer<B, never, A>, that: Layer.Layer<A, never, never>) => Layer.Layer<B, never, never> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const BLive: Layer.Layer<B, never, A>
BLive, import Layer
Layer.const fresh: <A, never, never>(self: Layer.Layer<A, never, never>) => Layer.Layer<A, never, never>
Creates a fresh version of this layer that will not be shared.
fresh(const ALive: Layer.Layer<A, never, never>
ALive)),41 import Layer
Layer.const provide: <A, never, C, never, never, A>(self: Layer.Layer<C, never, A>, that: Layer.Layer<A, never, never>) => Layer.Layer<C, never, never> (+3 overloads)
Feeds the output services of this builder into the input of the specified
builder, resulting in a new builder with the inputs of this builder as
well as any leftover inputs, and the outputs of the specified builder.
provide(const CLive: Layer.Layer<C, never, A>
CLive, import Layer
Layer.const fresh: <A, never, never>(self: Layer.Layer<A, never, never>) => Layer.Layer<A, never, never>
Creates a fresh version of this layer that will not be shared.
fresh(const ALive: Layer.Layer<A, never, never>
ALive))42 )43)44
45import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const runnable: Effect.Effect<void, never, never>
runnable)46/*47Output:48timestamp=... level=INFO fiber=#2 message=initialized49timestamp=... level=INFO fiber=#3 message=initialized50*/
If we don’t provide a layer globally but instead provide them locally, that layer doesn’t support memoization by default.
Example
In the following example, we provided the ALive
layer two times locally, and Effect doesn’t memoize the construction of the ALive
layer.
So, it will be initialized two times:
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3class class A
A extends import Context
Context.const Tag: <"A">(id: "A") => <Self, Shape>() => Context.TagClass<Self, "A", Shape>
namespace Tag
Tag("A")<class A
A, { readonly (property) a: number
a: number }>() {}4
5const const Alive: Layer.Layer<A, never, never>
Alive = import Layer
Layer.const effect: <typeof A, never, never>(tag: typeof A, effect: Effect.Effect<{
readonly a: number;
}, never, never>) => Layer.Layer<A, never, never> (+1 overload)
Constructs a layer from the specified effect.
effect(6 class A
A,7 import Effect
Effect.const succeed: <{
a: number;
}>(value: {
a: number;
}) => Effect.Effect<{
a: number;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({ (property) a: number
a: 5 }).(method) Pipeable.pipe<Effect.Effect<{
a: number;
}, never, never>, Effect.Effect<{
a: number;
}, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
a: number;
}, never, never>) => Effect.Effect<{
a: number;
}, never, never>): Effect.Effect<...> (+21 overloads)
pipe(8 import Effect
Effect.const tap: <{
a: number;
}, Effect.Effect<void, never, never>>(f: (a: {
a: number;
}) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<{
a: number;
}, E, R>) => Effect.Effect<...> (+7 overloads)
tap(() => import Effect
Effect.const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>
Logs one or more messages or error causes at the current log level, which is INFO by default.
This function allows logging multiple items at once and can include detailed error information using `Cause` instances.
To adjust the log level, use the `Logger.withMinimumLogLevel` function.
log("initialized"))9 )10)11
12const const program: Effect.Effect<void, never, never>
program = import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly a: number;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<{
readonly a: number;
}, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {13 yield* import Effect
Effect.const provide: <{
readonly a: number;
}, never, A, A, never, never>(self: Effect.Effect<{
readonly a: number;
}, never, A>, layer: Layer.Layer<A, never, never>) => Effect.Effect<{
readonly a: number;
}, never, never> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(class A
A, const Alive: Layer.Layer<A, never, never>
Alive)14 yield* import Effect
Effect.const provide: <{
readonly a: number;
}, never, A, A, never, never>(self: Effect.Effect<{
readonly a: number;
}, never, A>, layer: Layer.Layer<A, never, never>) => Effect.Effect<{
readonly a: number;
}, never, never> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(class A
A, const Alive: Layer.Layer<A, never, never>
Alive)15})16
17import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const program: Effect.Effect<void, never, never>
program)18/*19Output:20timestamp=... level=INFO fiber=#0 message=initialized21timestamp=... level=INFO fiber=#0 message=initialized22*/
We can memoize a layer manually using the Layer.memoize
function.
It will return a scoped effect that, if evaluated, will return the lazily computed result of this layer.
Example
1import { import Effect
Effect, import Context
Context, import Layer
Layer } from "effect"2
3class class A
A extends import Context
Context.const Tag: <"A">(id: "A") => <Self, Shape>() => Context.TagClass<Self, "A", Shape>
namespace Tag
Tag("A")<class A
A, { readonly (property) a: number
a: number }>() {}4
5const const ALive: Layer.Layer<A, never, never>
ALive = import Layer
Layer.const effect: <typeof A, never, never>(tag: typeof A, effect: Effect.Effect<{
readonly a: number;
}, never, never>) => Layer.Layer<A, never, never> (+1 overload)
Constructs a layer from the specified effect.
effect(6 class A
A,7 import Effect
Effect.const succeed: <{
a: number;
}>(value: {
a: number;
}) => Effect.Effect<{
a: number;
}, never, never>
Creates an `Effect` that succeeds with the provided value.
Use this function to represent a successful computation that yields a value of type `A`.
The effect does not fail and does not require any environmental context.
succeed({ (property) a: number
a: 5 }).(method) Pipeable.pipe<Effect.Effect<{
a: number;
}, never, never>, Effect.Effect<{
a: number;
}, never, never>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<{
a: number;
}, never, never>) => Effect.Effect<{
a: number;
}, never, never>): Effect.Effect<...> (+21 overloads)
pipe(8 import Effect
Effect.const tap: <{
a: number;
}, Effect.Effect<void, never, never>>(f: (a: {
a: number;
}) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<{
a: number;
}, E, R>) => Effect.Effect<...> (+7 overloads)
tap(() => import Effect
Effect.const log: (...message: ReadonlyArray<any>) => Effect.Effect<void, never, never>
Logs one or more messages or error causes at the current log level, which is INFO by default.
This function allows logging multiple items at once and can include detailed error information using `Cause` instances.
To adjust the log level, use the `Logger.withMinimumLogLevel` function.
log("initialized"))9 )10)11
12const const program: Effect.Effect<void, never, never>
program = import Effect
Effect.const scoped: <void, never, Scope>(effect: Effect.Effect<void, never, Scope>) => Effect.Effect<void, never, never>
Scopes all resources used in this workflow to the lifetime of the workflow,
ensuring that their finalizers are run as soon as this workflow completes
execution, whether by success, failure, or interruption.
scoped(13 import Layer
Layer.const memoize: <never, never, A>(self: Layer.Layer<A, never, never>) => Effect.Effect<Layer.Layer<A, never, never>, never, Scope>
Returns a scoped effect that, if evaluated, will return the lazily computed
result of this layer.
memoize(const ALive: Layer.Layer<A, never, never>
ALive).(method) Pipeable.pipe<Effect.Effect<Layer.Layer<A, never, never>, never, Scope>, Effect.Effect<void, never, Scope>>(this: Effect.Effect<...>, ab: (_: Effect.Effect<Layer.Layer<A, never, never>, never, Scope>) => Effect.Effect<...>): Effect.Effect<...> (+21 overloads)
pipe(14 import Effect
Effect.const andThen: <Layer.Layer<A, never, never>, Effect.Effect<void, never, never>>(f: (a: Layer.Layer<A, never, never>) => Effect.Effect<void, never, never>) => <E, R>(self: Effect.Effect<...>) => Effect.Effect<...> (+3 overloads)
Executes a sequence of two actions, typically two `Effect`s, where the second action can depend on the result of the first action.
The `that` action can take various forms:
- a value
- a function returning a value
- a promise
- a function returning a promise
- an effect
- a function returning an effect
andThen(((parameter) memoized: Layer.Layer<A, never, never>
memoized) =>15 import Effect
Effect.const gen: <YieldWrap<Effect.Effect<{
readonly a: number;
}, never, never>>, void>(f: (resume: Effect.Adapter) => Generator<YieldWrap<Effect.Effect<{
readonly a: number;
}, never, never>>, void, never>) => Effect.Effect<...> (+1 overload)
gen(function* () {16 yield* import Effect
Effect.const provide: <{
readonly a: number;
}, never, A, A, never, never>(self: Effect.Effect<{
readonly a: number;
}, never, A>, layer: Layer.Layer<A, never, never>) => Effect.Effect<{
readonly a: number;
}, never, never> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(class A
A, (parameter) memoized: Layer.Layer<A, never, never>
memoized)17 yield* import Effect
Effect.const provide: <{
readonly a: number;
}, never, A, A, never, never>(self: Effect.Effect<{
readonly a: number;
}, never, A>, layer: Layer.Layer<A, never, never>) => Effect.Effect<{
readonly a: number;
}, never, never> (+9 overloads)
Splits the context into two parts, providing one part using the
specified layer/context/runtime and leaving the remainder `R0`
provide(class A
A, (parameter) memoized: Layer.Layer<A, never, never>
memoized)18 })19 )20 )21)22
23import Effect
Effect.const runPromise: <void, never>(effect: Effect.Effect<void, never, never>, options?: {
readonly signal?: AbortSignal;
} | undefined) => Promise<void>
Executes an effect and returns a `Promise` that resolves with the result.
Use `runPromise` when working with asynchronous effects and you need to integrate with code that uses Promises.
If the effect fails, the returned Promise will be rejected with the error.
runPromise(const program: Effect.Effect<void, never, never>
program)24/*25Output:26timestamp=... level=INFO fiber=#0 message=initialized27*/