Skip to content

Flow Control

Branching, loops, parallelism, subflows, triggers, and error handling.

24 modules

ModuleDescription
Grup İşlemiÖğeleri yapılandırılabilir boyutta gruplar halinde işleyin
Dalİfade değerlendirmesine dayalı koşullu dallanma
Kesme Noktasıİnsan onayı veya girişi için iş akışı yürütmesini duraklat
Devre KesiciKademeli hataları önlemek için devre kesici deseni
KapsayıcıKarmaşık iş akışlarını düzenlemek için gömülü alt akış kapsayıcısı
GecikmeHızlı tekrarlanan çağrıları önlemek için yürütmeyi geciktir
BitişAçık iş akışı bitiş düğümü
Hata İşleyiciYukarı akış düğümlerinden gelen hataları yakalar ve işler
Hata İş Akışı TetikleyicisiHata iş akışları için giriş noktası - başka bir iş akışı başarısız olduğunda tetiklenir
Her Biri İçinBir liste üzerinde yinele ve her öğe için adımları yürüt
ÇatallaYürütmeyi paralel dallara böl
GitBaşka bir adıma koşulsuz atlama
Invoke WorkflowExecute an external workflow file
BirleştirParalel dalların tamamlanmasını bekle
DöngüÇıktı port yönlendirmesi kullanarak adımları N kez tekrarla
BirleştirBirden fazla girdiyi tek bir çıktıya birleştir
ParalelFarklı stratejilerle birden fazla görevi paralel olarak yürütün
Hız SınırıToken bucket veya kayar pencere kullanarak yürütmeyi sınırla
Yeniden DeneBaşarısız işlemleri yapılandırılabilir geri çekilme ile yeniden dene
BaşlangıçAçık iş akışı başlangıç düğümü
Alt AkışHarici bir iş akışına başvur ve yürüt
AnahtarDeğer eşleşmesine dayalı çok yollu dallanma
SınırlamaMinimum aralıkla yürütme hızını sınırlayın
Tetikleyiciİş akışı giriş noktası - manuel, webhook, zamanlama veya olay

Modules

Grup İşlemi

flow.batch

Öğeleri yapılandırılabilir boyutta gruplar halinde işleyin

Parameters:

NameTypeRequiredDefaultDescription
itemsarrayYes-Array of items to process. Can be numbers, strings, or objects.
batch_sizenumberYes10Grup başına öğe sayısı
delay_msnumberNo0Gruplar arasında bekleme süresi (hız sınırlaması için)
continue_on_errorbooleanNoFalseBir hata oluşursa kalan grupları işlemeye devam et
parallel_batchesnumberNo1Bir hata oluşursa kalan grupları işlemeye devam et

Output:

FieldTypeDescription
__event__stringParalel işlenecek grup sayısı (ardışık için 1)
batcharrayYönlendirme için olay (grup/tamamlandı/hata)
batch_indexnumberYönlendirme için olay (grup/tamamlandı/hata)
total_batchesnumberMevcut grup öğeleri
total_itemsnumberMevcut grup indeksi (0 tabanlı)
is_last_batchbooleanToplam grup sayısı
progressobjectToplam öğe sayısı

Example: Example

yaml
items: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
batch_size: 10

Example: Example

yaml
items: ${input.records}
batch_size: 100
delay_ms: 1000

Example: Example

yaml
items: ${input.data}
batch_size: 50
parallel_batches: 3
continue_on_error: true

Dal

flow.branch

İfade değerlendirmesine dayalı koşullu dallanma

Parameters:

NameTypeRequiredDefaultDescription
conditionstringYes-Expression to evaluate (supports ==, !=, >, <, >=, <=, contains)

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (true/false/error)
outputsobjectPort bazında çıktı değerleri
resultbooleanDal sonucu
conditionstringKoşul değeri
resolved_conditionstringKoşul değerlendirme sonucu

Example: Example

yaml
condition: ${search_step.count} > 0

Example: Example

yaml
condition: ${api_call.status} == success

Kesme Noktası

flow.breakpoint

İnsan onayı veya girişi için iş akışı yürütmesini duraklat

Parameters:

NameTypeRequiredDefaultDescription
titlestringNoApproval RequiredTitle displayed to approvers
descriptionstringNo-Optional description text
timeout_secondsnumberNo0Maximum wait time (0 for no timeout)
required_approversarrayYes-Array of data items to process
approval_modeselect (single, all, majority, first)NosingleHow approvals are counted
custom_fieldsarrayYes-Array of data items to process
include_contextbooleanNoTrueWhether to include execution context
auto_approve_conditionstringNo-Text content to process

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (approved/rejected/timeout)
breakpoint_idstringKesme noktası kimliği
statusstringDurum
approved_byarrayOnaylayan
rejected_byarrayReddeden
custom_inputsobjectÖzel girdi değerleri
commentsarrayİnceleme yorumları
resolved_atstringÇözüm zamanı
wait_duration_msintegerBekleme süresi (ms)

Example: Example

yaml
title: Approve data export
description: Please review and approve the data export

Example: Example

yaml
title: Manager Approval Required
description: Large transaction requires manager approval
required_approvers: ["manager@example.com"]
timeout_seconds: 3600

Example: Example

yaml
title: Adjustment Required
custom_fields: [{"name": "reason", "label": "Reason", "type": "text", "required": true}, {"name": "amount", "label": "Amount", "type": "number", "required": true}]

Devre Kesici

flow.circuit_breaker

Kademeli hataları önlemek için devre kesici deseni

Parameters:

NameTypeRequiredDefaultDescription
failure_thresholdnumberYes5Devrenin açılmasından önceki hata sayısı
reset_timeout_msnumberNo60000Devrenin yarı açık duruma geçmesinden önceki süre (milisaniye)
half_open_maxnumberNo1Yarı açık durumda izin verilen maksimum istek

Output:

FieldTypeDescription
__event__stringYönlendirme için etkinlik (izin verildi/reddedildi/yarı açık)
statestringDevre durumu (kapalı/açık/yarı açık)
failure_countnumberArdışık hata sayısı
last_failure_time_msnumberSon hatanın zaman damgası (milisaniye)
time_until_half_open_msnumberDevrenin yarı açık duruma geçmesine kadar geçen milisaniye

Example: Example

yaml
failure_threshold: 5
reset_timeout_ms: 60000

Example: Example

yaml
failure_threshold: 2
reset_timeout_ms: 10000
half_open_max: 1

Example: Example

yaml
failure_threshold: 20
reset_timeout_ms: 120000
half_open_max: 3

Kapsayıcı

flow.container

Karmaşık iş akışlarını düzenlemek için gömülü alt akış kapsayıcısı

Parameters:

NameTypeRequiredDefaultDescription
subflowobjectNo{'nodes': [], 'edges': []}Embedded workflow definition with nodes and edges
inherit_contextbooleanNoTrueWhether to inherit variables from parent workflow
isolated_variablesarrayYes-Array of data items to process
export_variablesarrayYes-Array of data items to process

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (success/error)
outputsobjectPort bazında çıktı değerleri
subflow_resultobjectAlt akış sonucu
exported_variablesobjectDışa aktarılan değişkenler
node_countintegerDüğüm sayısı
execution_time_msnumberYürütme süresi (ms)

Example: Example

yaml
subflow: {"nodes": [], "edges": []}
inherit_context: true

Example: Example

yaml
subflow: {"nodes": [], "edges": []}
inherit_context: false

Gecikme

flow.debounce

Hızlı tekrarlanan çağrıları önlemek için yürütmeyi geciktir

Parameters:

NameTypeRequiredDefaultDescription
delay_msnumberYes-Son çağrıdan sonra yürütme için bekleme süresi
leadingbooleanNoFalseÖncü kenarda yürüt (ilk çağrı hemen tetikler)
trailingbooleanNoTrueArdıl kenarda yürüt (gecikme süresi dolduktan sonra)

Output:

FieldTypeDescription
__event__stringYönlendirme için etkinlik (yürütüldü/geciktirildi)
last_call_msnumberSon çağrının zaman damgası (milisaniye)
calls_debouncednumberSon yürütmeden bu yana geciktirilen çağrı sayısı
time_since_last_msnumberSon çağrıdan bu yana geçen süre (milisaniye)
edgestringHangi kenarın yürütmeyi tetiklediği (öncü/ardıl)

Example: Example

yaml
delay_ms: 500

Example: Example

yaml
delay_ms: 1000
leading: true
trailing: false

Example: Example

yaml
delay_ms: 2000
leading: true
trailing: true

Bitiş

flow.end

Açık iş akışı bitiş düğümü

Parameters:

NameTypeRequiredDefaultDescription
output_mappingobjectNo{}Map internal variables to workflow output
success_messagestringNo-Text content to process

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (end)
ended_atstringBitiş zamanı
workflow_resultobjectİş akışı sonucu

Example: Example

yaml

Example: Example

yaml
output_mapping: {"result": "${process.output}", "status": "success"}

Hata İşleyici

flow.error_handle

Yukarı akış düğümlerinden gelen hataları yakalar ve işler

Parameters:

NameTypeRequiredDefaultDescription
actionstringYeslog_and_continueHata ile ne yapılacağı
include_tracebackbooleanNoTrueÇıkışa tam yığın izini dahil et
error_code_mappingobjectNo{}Çıkışa tam yığın izini dahil et
fallback_valueanyNo-Hata kodlarını özel eylemlerle eşle

Output:

FieldTypeDescription
__event__stringHata bastırıldığında kullanılacak değer
outputsobjectYönlendirme için olay (işlendi/yükselt)
error_infoobjectYönlendirme için olay (işlendi/yükselt)
action_takenstringAlınan eylem

Example: Example

yaml
action: log_and_continue
include_traceback: true

Example: Example

yaml
action: suppress
fallback_value: {"status": "skipped", "reason": "upstream_error"}

Example: Example

yaml
action: transform
error_code_mapping: {"TIMEOUT": {"retry": true, "delay": 5000}, "NOT_FOUND": {"skip": true}}

Hata İş Akışı Tetikleyicisi

flow.error_workflow_trigger

Hata iş akışları için giriş noktası - başka bir iş akışı başarısız olduğunda tetiklenir

Parameters:

NameTypeRequiredDefaultDescription
descriptionstringNo-Description of this error workflow

Output:

FieldTypeDescription
__event__stringBu hata iş akışının açıklaması
error_contextobjectYönlendirme için olay (tetiklendi)
triggered_atstringHata iş akışının tetiklendiği ISO zaman damgası

Example: Example

yaml
description: Send Slack notification on workflow failure

Example: Example

yaml
description: Log all workflow errors to monitoring system

Her Biri İçin

flow.foreach

Bir liste üzerinde yinele ve her öğe için adımları yürüt

Parameters:

NameTypeRequiredDefaultDescription
itemsstringYes-Üzerinde yinelenecek öğeler listesi (${variable} referansı destekler)
stepsarrayNo-Her öğe için yürütülecek adımlar
item_varstringNoitemGeçerli öğe için değişken adı
index_varstringNoindexGeçerli indeks için değişken adı
output_modestringNocollectSonuç toplama modu

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (iterate/done)
__set_contextobjectBağlam ayarla
outputsobjectPort bazında çıktı değerleri
iterationnumberGeçerli yineleme indeksi
statusstringİşlem durumu
resultsarrayToplanan sonuçlar
countnumberToplam öğe sayısı

Example: Example

yaml
items: ${steps.csv.result.data}

Example: Example

yaml
items: ${search_results}
item_var: element
steps: [{"module": "element.text", "params": {"element_id": "${element}"}, "output": "text"}]

Çatalla

flow.fork

Yürütmeyi paralel dallara böl

Parameters:

NameTypeRequiredDefaultDescription
branch_countnumberNo2Number of parallel branches

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (fork/error)
input_dataanyGirdi verileri
branch_countintegerDal sayısı

Example: Example

yaml
branch_count: 2

Example: Example

yaml
branch_count: 3

Git

flow.goto

Başka bir adıma koşulsuz atlama

Parameters:

NameTypeRequiredDefaultDescription
targetstringYes-Step ID to jump to
max_iterationsnumberNo100Maximum number of iterations (prevents infinite loops)

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (goto)
targetstringHedef adım
iterationnumberYineleme sayısı

Example: Example

yaml
target: fetch_next_page
max_iterations: 10

Example: Example

yaml
target: cleanup_step

Invoke Workflow

flow.invoke

Execute an external workflow file

Parameters:

NameTypeRequiredDefaultDescription
workflow_sourcestringYes-File path to workflow YAML or inline YAML content
workflow_paramsobjectYes-Parameters to pass to the invoked workflow
timeout_secondsnumberNo300Maximum execution time in seconds
output_mappingobjectNo{}Map internal variables to workflow output

Output:

FieldTypeDescription
__event__stringParameters to pass to the invoked workflow
resultanyMaximum execution time in seconds
workflow_idstringEvent for routing (success/error)
execution_time_msnumberWorkflow execution result

Example: Example

yaml
workflow_source: workflows/validate_order.yaml
workflow_params: {"order_id": "${input.order_id}"}
timeout_seconds: 60

Example: Example

yaml
workflow_source: workflows/process_data.yaml
workflow_params: {"data": "${input.data}"}
output_mapping: {"processed": "result.data"}

Birleştir

flow.join

Paralel dalların tamamlanmasını bekle

Parameters:

NameTypeRequiredDefaultDescription
strategyselect (all, any, first)NoallHow to handle multiple inputs
input_countnumberNo2Number of ports
timeoutnumberNo60000Maximum time to wait in milliseconds
cancel_pendingbooleanNoTrueCancel pending branches when using first strategy

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (joined/timeout/error)
joined_dataarrayBirleştirilmiş veriler
completed_countintegerTamamlanan dal sayısı
strategystringBirleştirme stratejisi

Example: Example

yaml
strategy: all
input_count: 2
timeout_ms: 30000

Example: Example

yaml
strategy: first
input_count: 3
cancel_pending: true

Döngü

flow.loop

Çıktı port yönlendirmesi kullanarak adımları N kez tekrarla

Parameters:

NameTypeRequiredDefaultDescription
timesnumberYes1Tekrar sayısı
targetstringNo-Hedef adım (kullanımdan kaldırıldı)
stepsarrayNo-Her yineleme için yürütülecek adımlar
index_varstringNoindexGeçerli indeks için değişken adı

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (iterate/done)
outputsobjectPort bazında çıktı değerleri
iterationnumberGeçerli yineleme
statusstringİşlem durumu
resultsarrayToplanan sonuçlar
countnumberToplam yineleme

Example: Example

yaml
times: 3

Example: Example

yaml
times: 5
steps: [{"module": "browser.click", "params": {"selector": ".next"}}]

Birleştir

flow.merge

Birden fazla girdiyi tek bir çıktıya birleştir

Parameters:

NameTypeRequiredDefaultDescription
strategyselect (first, last, all)NoallHow to merge multiple inputs
input_countnumberNo2Number of ports

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (merged/error)
merged_dataanyBirleştirilmiş veriler
input_countintegerGirdi sayısı
strategystringBirleştirme stratejisi

Example: Example

yaml
strategy: all
input_count: 3

Example: Example

yaml
strategy: first
input_count: 2

Paralel

flow.parallel

Farklı stratejilerle birden fazla görevi paralel olarak yürütün

Parameters:

NameTypeRequiredDefaultDescription
tasksarrayYes-Paralel olarak yürütülecek görev tanımlarının dizisi
modestringNoallParalel olarak yürütülecek görev tanımlarının dizisi
timeout_msnumberNo60000Maximum wait time in milliseconds
fail_fastbooleanNoTrueİlk hatada tüm görevleri durdur (sadece mode=all için)
concurrency_limitnumberNo0İlk hatada tüm görevleri durdur (sadece mode=all için)

Output:

FieldTypeDescription
__event__stringMaksimum eşzamanlı görev sayısı (sınırsız için 0)
resultsarrayYönlendirme için olay (tamamlandı/kısmi/hata)
completed_countnumberYönlendirme için olay (tamamlandı/kısmi/hata)
failed_countnumberTüm görevlerin sonuçları
total_countnumberBaşarıyla tamamlanan görev sayısı
modestringBaşarısız görev sayısı
duration_msnumberToplam görev sayısı

Example: Example

yaml
tasks: [{"module": "http.get", "params": {"url": "https://api1.example.com"}}, {"module": "http.get", "params": {"url": "https://api2.example.com"}}]
mode: all
timeout_ms: 30000

Example: Example

yaml
tasks: [{"module": "http.get", "params": {"url": "https://mirror1.example.com"}}, {"module": "http.get", "params": {"url": "https://mirror2.example.com"}}]
mode: race

Example: Example

yaml
tasks: [{"module": "http.get", "params": {"url": "https://api1.example.com"}}, {"module": "http.get", "params": {"url": "https://might-fail.example.com"}}]
mode: settle

Hız Sınırı

flow.rate_limit

Token bucket veya kayar pencere kullanarak yürütmeyi sınırla

Parameters:

NameTypeRequiredDefaultDescription
max_requestsnumberYes-Pencere başına izin verilen maksimum istek sayısı
window_msnumberNo60000Zaman penceresi (milisaniye)
strategystringNotoken_bucketHız sınırlama stratejisi (token_bucket veya kayar_pencere)
queue_overflowstringNowaitKuyruk dolduğunda davranış (bırak veya hata)

Output:

FieldTypeDescription
__event__stringYönlendirme için etkinlik (izin verildi/sınırlı)
tokens_remainingnumberKovadaki kalan jetonlar
window_reset_msnumberPencerenin sıfırlanmasına kadar geçen milisaniye
requests_in_windownumberMevcut penceredeki istek sayısı
wait_msnumberBir sonraki izin verilen istek için bekleme süresi (milisaniye)

Example: Example

yaml
max_requests: 100
window_ms: 60000
strategy: token_bucket

Example: Example

yaml
max_requests: 10
window_ms: 1000
strategy: fixed_window
queue_overflow: error

Example: Example

yaml
max_requests: 50
window_ms: 30000
strategy: sliding_window
queue_overflow: wait

Yeniden Dene

flow.retry

Başarısız işlemleri yapılandırılabilir geri çekilme ile yeniden dene

Parameters:

NameTypeRequiredDefaultDescription
max_retriesnumberYes3Maksimum yeniden deneme deneme sayısı
initial_delay_msnumberNo1000İlk yeniden deneme öncesi başlangıç gecikmesi (milisaniye)
backoff_multipliernumberNo2.0Üstel geri çekilme için çarpan
max_delay_msnumberNo30000Yeniden denemeler arasındaki maksimum gecikme (milisaniye)
retry_on_errorsarrayNo[]Yeniden denenecek hata türleri (boşsa hepsi yeniden denenir)

Output:

FieldTypeDescription
__event__stringYönlendirme için olay (yeniden dene/başarılı/başarısız)
attemptnumberMevcut deneme numarası
max_retriesnumberYapılandırılmış maksimum yeniden deneme sayısı
delay_msnumberSonraki yeniden deneme öncesi gecikme (milisaniye)
total_elapsed_msnumberToplam geçen süre (milisaniye)
last_errorobjectSon hata mesajı

Example: Example

yaml
max_retries: 3

Example: Example

yaml
max_retries: 10
initial_delay_ms: 500
backoff_multiplier: 1.5
max_delay_ms: 10000

Example: Example

yaml
max_retries: 5
initial_delay_ms: 2000
retry_on_errors: ["TIMEOUT", "RATE_LIMIT", "429", "503"]

Başlangıç

flow.start

Açık iş akışı başlangıç düğümü

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (start)
started_atstringBaşlangıç zamanı
workflow_idstringİş akışı kimliği

Example: Example

yaml

Alt Akış

flow.subflow

Harici bir iş akışına başvur ve yürüt

Parameters:

NameTypeRequiredDefaultDescription
workflow_refstringYes-Text content to process
execution_modeselect (inline, spawn, async)NoinlineSelect an option
input_mappingobjectYes-Data object to process
output_mappingobjectNo{}Map internal variables to workflow output
timeoutnumberNo300000Maximum time to wait in milliseconds

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (success/error)
resultanyYürütme sonucu
execution_idstringYürütme kimliği
workflow_refstringİş akışı referansı

Example: Example

yaml
workflow_ref: workflows/validate_order
execution_mode: inline
input_mapping: {"order_data": "${input.order}"}
output_mapping: {"validation_result": "result"}

Example: Example

yaml
workflow_ref: workflows/send_notifications
execution_mode: spawn

Anahtar

flow.switch

Değer eşleşmesine dayalı çok yollu dallanma

Parameters:

NameTypeRequiredDefaultDescription
expressionstringYes-Value to match against cases (supports variable reference)
casesarrayYes[{'id': 'case_1', 'value': 'case1', 'label': 'Case 1'}]List of case definitions

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (case:value veya default)
outputsobjectPort bazında çıktı değerleri
matched_casestringEşleşen durum
valueanyEşleşen değer

Example: Example

yaml
expression: ${api_response.status}
cases: [{"id": "case-1", "value": "success", "label": "Success"}, {"id": "case-2", "value": "pending", "label": "Pending"}, {"id": "case-3", "value": "error", "label": "Error"}]

Example: Example

yaml
expression: ${input.type}
cases: [{"id": "img", "value": "image", "label": "Image"}, {"id": "vid", "value": "video", "label": "Video"}, {"id": "txt", "value": "text", "label": "Text"}]

Sınırlama

flow.throttle

Minimum aralıkla yürütme hızını sınırlayın

Parameters:

NameTypeRequiredDefaultDescription
interval_msnumberYes-Yürütmeler arasındaki minimum süre (milisaniye)
leadingbooleanNoTrueÖncü kenarda yürüt (ilk çağrı hemen geçer)

Output:

FieldTypeDescription
__event__stringYönlendirme için olay (yürütüldü/sınırlı)
last_execution_msnumberSon izin verilen yürütmenin zaman damgası
calls_throttlednumberSon yürütmeden bu yana sınırlanan çağrı sayısı
time_since_last_msnumberSon yürütmeden bu yana geçen süre (milisaniye)
remaining_msnumberBir sonraki yürütmeye izin verilene kadar kalan milisaniye

Example: Example

yaml
interval_ms: 1000

Example: Example

yaml
interval_ms: 200
leading: true

Example: Example

yaml
interval_ms: 5000
leading: false

Tetikleyici

flow.trigger

İş akışı giriş noktası - manuel, webhook, zamanlama veya olay

Parameters:

NameTypeRequiredDefaultDescription
trigger_typeselect (manual, webhook, schedule, event, mcp, polling)NomanualType of trigger event
webhook_pathstringNo-URL path for webhook trigger
schedulestringNo-Cron expression for scheduled trigger
event_namestringNo-Event name to listen for
tool_namestringNo-MCP tool name exposed to AI agents
tool_descriptionstringNo-Description shown to AI agents for this tool
poll_urlstringNo-API endpoint to poll for changes
poll_intervalnumberNo300How often to check for changes (minimum 60 seconds)
poll_methodselect (GET, POST)NoGETHTTP method for polling request
poll_headersobjectNo{}Custom headers for polling request (e.g. API keys)
poll_bodyobjectNo{}Request body for POST polling
dedup_keystringNo-JSON path to extract a unique value for deduplication
configobjectNo-Custom trigger config (for composites: LINE BOT, Telegram, Slack, etc.)
descriptionstringNo-Optional description text

Output:

FieldTypeDescription
__event__stringYönlendirme olayı (triggered/error)
trigger_dataobjectTetikleyici verileri
trigger_typestringTetikleyici türü
triggered_atstringTetiklenme zamanı

Example: Example

yaml
trigger_type: manual

Example: Example

yaml
trigger_type: webhook
webhook_path: /api/webhooks/order-created

Example: Example

yaml
trigger_type: schedule
schedule: 0 * * * *

Example: Example

yaml
trigger_type: mcp
tool_name: send-report
tool_description: Send a weekly summary report

Example: Example

yaml
trigger_type: polling
poll_url: https://api.example.com/items
poll_interval: 300
dedup_key: $.data[0].id

Released under the Apache 2.0 License.